📖

ES6で追加された機能についておさらい

2024/04/25に公開

ES6とは

ES6とはJavaScriptのバージョンで、正式にはECMAScript2015といいます。
2015年に公開されたこのバージョンでは多数の機能追加と改善がされました。

変数宣言

ES6以前はvarで変数宣言してましたが、ES6以降はletconstで変数宣言を行います。

let

  • ブロックスコープの局所変数を宣言するために使用します。
  • 任意で値を代入して初期化できます。
let hoge = "hoge";
hoge(); // => "hoge"
  • 再宣言不可で再代入可能です。
  • ブロックの文か式にスコープを限定した変数を宣言することができます。
let hoge = "hoge";
hoge(); // => "hoge"

hoge = "huga";
hoge(); // => "hoge"

let hoge = 'piyo'; // 再宣言するとエラーになる

const

  • ブロックスコープの定数を宣言するために使用されます。
  • 再宣言、再代入不可です。
  • オブジェクトの場合はプロパティを追加/更新/削除可能です。
const hoge = "hoge";
hoge() // => "hoge"

hoge = "huga" // => 再代入するとエラーになる
const hoge = "piyo" // => 再宣言するとエラーになる

アロー関数

これまではfunctionで関数を記述していましたが、ES6以降は代わりにアロー関数で記述していくことになります。
アロー関数とは、名前の通り、アロー(矢)を使って関数を記述する方法です。

(引数) => {関数本体}

functionとの比較

function sayHello(name) {
    const hello = "Hello, " + name + "!"
    return hello
}

const sayHello = (name) => {
    const hello = "Hello, " + name + "!"
    return hello
}

シンプルにアロー関数を記述する

アロー関数を使用すると条件次第でよりシンプルに記述できます。
本文が1行の場合、{...}を省略できます。
また、文の戻り値もそのまま戻り値となるため、returnも省略できます。

const sayHello = name => "Hello, " + name + "!"

クラス

JavaScriptでは以前はclassはなかったのでfunctionを使って実現していました。
ES6からclassが導入されたので他の言語同様にクラスを実現できるようになりました。

クラスの定義

クラスは、classキーワードとクラス名、そしてクラスの本体を囲む{}を使って定義されます。

class MyClass {
}

コンストラクタメソッド

constructorメソッドは、クラスで作成されたオブジェクトを作成し初期化するためのメソッドです。1つのクラス内にconstructorメソッドは一つだけ存在できます。

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

クラスの継承

クラス継承とは、あるクラス(親クラス)のプロパティやメソッドを別のクラス(子クラス)が受け継ぐことを可能にする概念です。既存コードの再利用、拡張が可能になります。
extendsでクラスの継承ができます。

class User {
  constructor(username, email) {
    this.username = username;
    this.email = email;
  }
  displayInfo() {
    console.log(`ユーザー名: ${this.username}, メールアドレス: ${this.email}`);
  }
}

モジュール

モジュールは、変数や関数などをまとめたもので、 JavaScriptにおいては、1つのモジュールは1つのJavaScriptファイルに対応します。
export文で変数や関数などをエクスポートできます。
import文で別のモジュールからエクスポートされたものをインポートできます。
インポートとエクスポートはそれぞれ、名前つき、デフォルト、という2つの方法があります。

名前つきエクスポート/インポート

名前つきエクスポートは、モジュールから複数の値をエクスポートする場合に使用されます。エクスポートされる各値には固有の名前がつけられます。これにより、インポートする側は必要な値を選択して読み込むことができるようになります。

名前付きエクスポート

export const foo = "foo";
export const bar = () => "bar"

名前付きインポート

import { foo, bar } from "./module.js";
console.log(foo); // => "foo"
console.log(bar()); // => "bar"

デフォルトエクスポート/インポート

デフォルトエクスポートは、モジュールごとに1つのデフォルトエクスポートしか設定できません。デフォルトエクスポートされた値は、インポートする際に任意の名前を付けることができます。

デフォルトエクスポート

const foo = "foo";
export default foo;

デフォルトインポート

// デフォルトエクスポートを任意の名前でインポートする
import module from "./module.js";
console.log(module); // => "foo"

プロミス

Promiseは非同期処理の最終的な完成または失敗を表すオブジェクトです。以下の3つの状態を持っています。
以下の3つの状態を持っています。

  • 非同期処理が成功した場合の「解決」(fulfilled)
  • 失敗した場合の「拒否」(rejected)
  • 処理がまだ完了していない「保留」(pending)
    Promiseが解決または拒否されると、それは「確定」(settled)状態となり、この状態からは変化しません。

promiseの基本的な使い方

Promiseオブジェクトは .then()、.catch()、.finally() のメソッドをチェーンすることで使用できます。.then() には2つの引数を取ることができ、1つ目はPromiseが解決されたとき、2つ目は拒否されたときに実行される関数です。
拒否時の処理は一般的には.catch()メソッドを使用して設定します。

then()

Promiseが解決されたときに実行される関数を受け取ります。また、その返り値を新しいPromiseとして次の .then() へ渡すこともできます。

catch()

Promiseが拒否されたときに実行される関数を設定します。

.finally()

Promiseの成功失敗に関わらず、最後に必ず実行される処理を設定します。

const promise = new Promise((resolve, reject) => {
  // 非同期処理
});

promise.then(result => {
  console.log(result);  // 解決時に実行される
}).catch(error => {
  console.error(error);  // 拒否時に実行される
}).finally(() => {
  console.log('処理が完了しました。');  // 成否に関わらず最後に実行される
});

プロミスのメソッド

Promiseには、複数の非同期処理を効率的に扱うメソッドがいくつかあります。

  • Promise.all
    • 複数の非同期処理がすべて完了するのを待ちたい場合に使用します。1つでも拒否された場合はPromise.allはそのエラーで拒否されます。
  • Promise.race
    • 複数の値を受け取り、いずれかのプロミスが解決または拒否されるとすぐにその結果で解決または拒否される新しいプロミスを返します。最初に確定したプロミスの結果のみが考慮されます。
  • Promise.allSettled
    • 複数の値を受け取り、すべてのプロミスが解決または拒否された後で解決する新しいプロミスを返します。各プロミスの結果は解決か拒否かにかかわらず報告されます。
  • Promise.any
    • 複数の値を受け取り、いずれかのプロミスが解決されるとすぐにその結果で解決される新しいプロミスを返します。すべてのプロミスが拒否された場合、Promise.anyはエラーで拒否されます。

よく使われるPromise.allの使用例を紹介します。

// Promise.all の例
const promise1 = Promise.resolve(6);
const promise2 = 32;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'hoge');
});

Promise.all([promise1, promise2, promise3]).then(values => {
  console.log(values);  // [6, 32, "hoge"]
}).catch(error => {
  console.error(`エラーが発生しました。 ${error}`);
});

デストラクチャリング

デストラクチャリングは、配列やオブジェクトからデータを簡単に取り出して、新しい変数に割り当てることができます。

配列のデストラクチャリング

配列から個々の要素を取り出して変数に割り当てることができます。

let fruits = ["リンゴ", "バナナ", "イチゴ"];
let [apple, banana, strawberry] = fruits;
console.log(apple); // => "リンゴ"

取り出したい要素をスキップすることも可能です。

let [first,, third] = fruits;
console.log(first); // => "リンゴ"
console.log(third); // => "イチゴ"

オブジェクトのデストラクチャリング

オブジェクトのプロパティを変数として抽出することができます。

let user = {name: "太郎", age: 25};
let {name, age} = user;
console.log(name); // => "太郎"

新しい変数名を指定してプロパティを割り当てることができます。

let {name: userName, age: userAge} = user;
console.log(userName); // => "太郎"

テンプレートリテラル

これまでのJavaScriptでは文字列を連結する際には+演算子を使用していましたが、テンプレートリテラルを使うことで、より直感的に、読みやすく文字列を組み立てることが可能になります。

使い方

バッククォート(`)を使って文字列を囲みます。
${}構文を用いて変数や式の値を埋め込むことができます。

let name = "太郎";
let greeting = `こんにちは、${name}さん!`;
console.log(greeting); // => "こんにちは、太郎さん!"

複数行の文字列

バッククォートを使用することで、改行を含む複数行の文字列を簡単に作成することができます。

let multiLineString = `おはようございます
こんにちは
こんばんは`;
console.log(multiLineString);

従来のJavaScriptでは、複数行の文字列を扱う際には、文字列を連結するか、特殊文字を使用して改行を表現する必要がありましたが、テンプレートリテラルを用いることで、直感的に複数行の文字列を扱うことが可能になります。

Symbolデータ型

Symbolは、ES6で追加された新しいデータ型です。Symbolは完全に一意な値を生成するためのプリミティブ型で、オブジェクトのプロパティのキーとして使われます。
symbolを使うとプロパティ名の衝突を避けることができ、特に大規模なコードベースやライブラリ間での名前の衝突を防ぐのに役立ちます。

基本的な使い方

Symbolを生成するには、Symbol()関数を使用します。この関数は常に一意のSymbolを返します。

let symbol1 = Symbol('hoge');
let symbol2 = Symbol('hoge');
console.log(sym1 === sym2); // false

イテレータとジェネレータ

イテレータとは

イテレータとは、繰り返し処理を実現するための下記特徴を持つオブジェクトです。
具体的には

  • next()メソッドを持っています。
  • valueとdoneを返します。
  • valueは次の値を返し、doneはループが継続する場合はfalse、終了する場合はtrueを返します。

イテラブルなオブジェクトとは

  • [Symbol.iterator]()というメソッドを持っているオブジェクトです。

  • 戻り値としてイテレータを返します。

  • for (...of...) などを使用しでループ参照することができます。

  • Array

  • String
    などもイテラブルな型に該当します。

ジェネレータとは

ジェネレータ(generator)はイテラブルなオブジェクトを簡単に生成できる仕組みです。
function*構文を使用して記述できます。

function* generateFnc() {
    yield 1;
    yield 2;
}

generateFnc()を呼び出すと“ジェネレーター”オブジェクトを返します。
この時点では関数のコードは実行されません。

ジェネレーターのnext()メソッドを実行するたびに、ジェネレーター関数内のyieldを順番に処理していきます。

スプレッド構文

スプレッド構文とは(...)を使った構文です。
配列や文字列など反復可能なオブジェクトをスプレッド構文を使用して展開することができます。

const hello = ['H','e','l','l','o'];
console.log(...hello); // => 'Hello'

その他の使い方

配列のコピーを作る

const numbers = [1, 2, 3];
const numbersCopy = [...numbers]; // [1, 2, 3]

配列を結合する

const moreNumbers = [4, 5, 6];
const combinedNumbers = [...numbers, ...moreNumbers]; // [1, 2, 3, 4, 5, 6]

オブジェクトを結合する

const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const combinedObj = { ...obj1, ...obj2 }; // { a: 1, b: 2, c: 3, d: 4 }

Discussion