はじめに
モダンフロント開発に必須の知識であるES2015〜以降の記法と、実務でよく使用される高階関数について、自分の中で改めて復習、整理しておきたいと思います。
それぞれの項目に★~★★★
の重要度も記述しています。
★★★
=> 必ず覚えておくべき
★★
=> 覚えておくべきだが、使う場面が限られる
★
=> 知識としては知っておいた方が良い
現在フロントエンドエンジニアの方やフロントエンジニアになりたての方、フロントエンドエンジニアを目指して勉強中の方に読んでいただけたら幸いです。
ES(ECMAScript)とは?
JavaScriptの標準仕様。
現在ブラウザで使われているJavaScriptは、ECMAScriptの仕様に則って開発されています。
JavaScriptは他の言語のようにversionなどが存在せず、「ECMAScriptのversion~~に対応しているJavaScript」というような扱いになっています。
なので、年々アップデートされるECMAScriptの仕様をインプットし続けることがフロントエンドエンジニアには必須となるのです。
特に、大きな変更があったES2015からの記法が現在のフロント開発の基盤となっているため、まとめてみました。
注意点
ECMASCriptの対応状況はブラウザによって違うので、今現在の、ブラウザのECMAScript対応状況をよく確認しておく必要があります。
※最新のESを古いESに変換することができる「トランスパイラ」についての説明は割愛いたします。
ES2015
変数宣言(let
、const
)
重要度 ★★★
ES2015が出るまではvar
による変数宣言のみだったが、再代入可能や、スコープがグローバルだったため、バグが多発する恐れがあった。
そこで新しい変数宣言のlet
、const
が追加される。
-
let
・・・再代入可能なブロックスコープのローカル変数宣言 -
const
・・・再代入不可能なブロックスコープのローカル変数宣言
// 再代入可能
let num = 1
num = 2
console.log(num) //=> 2
// 再代入不可能
const age = 18
age = 22 // NG
// ブロックスコープ(let、const共通)
let name = taro
{
let name = hana
console.log(name) //=> hana
}
console.log(name) //=> taro
基本的にはconstを使用し、どうしてもという場合のみletを使用するというのがベストだと思います。(varは使用しない)
クラス構文
重要度★
RubyやJavaでお馴染みのクラス構文がJavaScriptにも実装される。
constructor
、prototype
、static
という3つのメソッドとクラスの継承(extends
)が可能。
-
constructor
メソッド・・・クラスがnewされた時に実行されるメソッド -
prototype
メソッド・・・クラスのインスタンスから呼び出せるメソッド -
static
メソッド・・・インスタンスを生成しなくても呼び出せるメソッド
class Human {
// constructorメソッド
constructor(name) {
this.name = name;
}
// prototypeメソッド
hello() {
console.log('My name is ' + this.name);
}
// staticメソッド
static num_of_hands() {
console.log(2)
}
}
// prototypeメソッドの呼び出し
obj = new Human('Koyabu')
obj.hello() //=> 'My name is Koyabu'
// staticメソッドの呼び出し
Human.num_of_hands() //=> 2
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
// 継承
class Dog extends Animal {
speak() {
console.log(this.name + ' barks.');
}
}
注意点
クラス構文は、現在フロント開発で主流となっている、React、Vue、Svelteなどを使用した開発ではほとんど使われていないため、「重要度★」としています。
アロー関数
重要度★★★
従来のfunction
ではなく、=>
を用いた関数宣言。
- 匿名関数
- 引数が一つの場合は
()
が省略可能 - 単一式の場合は、
{}
やreturn
を省略できる
// 従来の関数
function (a, b){
return a + b + 100;
}
// アロー関数
(a, b) => a + b + 100;
const num = (a, b) => a + b + 100;
console.log(num(5, 10)) //=> 115
注意点
thisやsuperへの結びつけを持たないので、メソッドとして使用することができなかったり、コンストラクターとしても使用することは出来ません。
分割代入
重要度★★★
一度に複数の変数に、配列やオブジェクトなどの複数の値を代入できる。
また、オブジェクトのkeyとvalueの変数名が同じ時は省略することが可能に。
const [name, age] = ['Taro', 22];
console.log(name) //=> Taro
console.log(age) //=> 22
const hero = {name: 'Taro', age: 22}
const {name, age} = hero
console.log(name) //=> Taro
console.log(age) //=> 22
// keyとvalueの変数名が同じ時は省略可能
const user = {name: name, age: age} // ↓と同じ
const user = {name, age}
配列展開
重要度★★★
...(スプレッド構文)
を用いて、配列を展開することができる。
※ES2018より、オブジェクトにも...(スプレッド構文)
が使用できるようになりました。
const array = [1, 2, 3]
console.log([...array, 4, 5, 6]) //=> [1, 2, 3, 4, 5, 6]
// ES2018の項目で改めて紹介します。
const hero = {name: 'Taro', age: '22'}
console.log({...hero, weapon: 'sword'}) //=> {name: 'Taro', age: '22', weapon: 'sword'}
可変長引数
重要度★★
上記の配列展開
と同じく、...(スプレッド構文)
を使用することで、複数の引数を一つの配列で受け取ることができる。
配列展開
とは逆のイメージとも言える。
const f = (a, b, ...c) => {
console.log(a, b, c)
}
f(1, 2, 3, 4) //=> 1, 2, [3, 4]
デフォルト引数
重要度★★★
関数宣言時に引数に値を代入しておくことで、デフォルト引数
とすることができる。
const multiply = (a, b = 2) => {
console.log(a * b);
}
multiply(5); // 10
テンプレート文字列
重要度★★★
``で文字列を囲むことで、その中に ${}を使用し変数を記述できる。
const name = 'Taro'
const greet = `こんにちは!${name}さん!`
console.log(greet) //=> こんにちは!Taroさん!
非同期処理(Promise
)
重要度★★★
非同期処理を扱うオブジェクトPromise
。
Promise
にはPromiseStatus
と呼ばれる3つの状態がある。
-
pending
・・・未解決(処理が終わるのを待っている状態) -
resolved
・・・解決済み(処理が終わり解決した状態) -
rejected
・・・拒否(処理が失敗に終わってしまった状態)
const promise = new Promise((resolve, reject) => {});
const promise = new Promise((resolve, reject) => {
resolve("test");
}).then((val) => {
console.log(`then1: ${val}`);
return val;
}).catch((val) => {
console.log(`catch: ${val}`);
return val;
※Promiseに関しての詳しい説明は割愛いたします。
現在非同期処理を扱う場合は、ES2017で追加されたasync/awaitを使用するのが主流です。
Map
重要度★
キーと値の組み合わせからなる抽象データ型。
オブジェクトとほぼ同じだが、オブジェクトと違う点は2点。
-
Object
のprototype
オブジェクトからプロパティを継承されない - 文字列や
Symbol
以外の値もkeyとして使用できる
// Mapの作成
const map = new Map();
// 新しい要素の追加
map.set("name", "Taro");
console.log(map.size); // => 1
console.log(map.get("name")); // => "Taro"
Set
重要度★
重複する値がないことを保証したコレクション。
// Setの作成
const set = new Set();
// 値の追加
set.add("Taro");
console.log(set.size); // => 1
// 重複する値は追加されない
set.add("Taro");
console.log(set.size); // => 1
for..of
重要度★★
配列
、Map
、Set
などに対して、反復処理ができる。
const array1 = ['a', 'b', 'c'];
for (const element of array1) {
console.log(element);
}
//=> 'a'
//=> 'b'
//=> 'c'
注意点
配列に対する処理は、基本的に、後述する「高階関数」を使用するのが推奨です。
ES2016
Array.prototype.includes()
メソッド
重要度★★★
配列の中に指定した要素が含まれているかをbooleanで返す関数。
const array = ['a', 'b', 'c'];
console.log(array.includes('c')); //=> true
console.log(array.includes('d')); //=> false
指数演算子
重要度★★★
ES2016より、指数演算子**
と、それに伴う代入演算**=
が追加される。
console.log(2 ** 4); //=> 16
let a = 2, b = 3;
a **= b
console.log(a) //=> 8
ES2017
async / await
重要度★★★
Promise
を使った非同期処理に対して新しいシンタックス(構文)。
async
functionを定義し、その中の非同期処理にawait
を記述することで、非同期処理が完了するまで以降の処理を待ってくれる。
const fetchData = async () => {
try{
const data = await // awaitに続けて非同期処理を記述する
console.log(data) // ↑の非同期処理が完了するまでこの処理は実行されない
}catch(error){
console.log(error)
}
}
Object.values()
/ Object.entries()
メソッド
重要度★★★
オブジェクトに存在するキーを取り出す Object.keys()
に対応するメソッドとして、値を取り出す Object.values()
と キーバリューペアを取り出す Object.entries()
の2メソッドが追加された。
const obj = { a: 1, b: 2, c: 3 };
// キー一覧を取得
console.log(Object.keys(obj)); //=> ['a', 'b', 'c']
// 値一覧を取得
console.log(Object.values(obj)); //=> [1, 2, 3]
// キー、バリューのペアを配列で取得
console.log(Object.entries(obj)); //=> [['a', 1], ['b', 2], ['c', 3]]
String.prototype.padStart()
/ String.prototype.padEnd()
メソッド
重要度★
文字列を加工し、固定文字列長になるよう指定文字で空白を埋めてくれるメソッド。
-
padStart
・・・右寄せで左側を埋める -
padEnd
・・・左寄せで右側を埋める
"abc".padStart(10); // " abc"
"abc".padStart(6,"123465"); // "123abc"
"abc".padStart(8, "0"); // "00000abc"
"abc".padStart(1); // "abc"
"abc".padEnd(10); // "abc "
"abc".padEnd(6,"123465"); // "abc123"
"abc".padEnd(8, "0"); // "abc00000"
"abc".padEnd(1); // "abc"
ES2018
残余プロパティ / 分割プロパティ
重要度★★★
ES2015で追加された...(スプレッド構文)
がオブジェクトにも適用。
// 残余プロパティ
const {x, y, ...z} = {x: 1, y: 2, a: 3, b: 4, c: 5 };
console.log(x) // 1
console.log(y) // 2
console.log(z) // {a: 3, b: 4, c: 5}
// 分割プロパティ
const num = {x, y, ...z};
console.log(num) // {x: 1, y: 2, a: 3, b: 4, c: 5}
Promise.prototype.finally()
メソッド
重要度★★
明示的なfinally()
が追加。
finally()
で例外が発生した場合、再度Promise
が生成される。
const fetchData = async () => {
try{
const data = await // awaitに続けて非同期処理を記述
console.log(data)
}catch(error){
console.log(error)
}finally{
// ここにfinallyの処理が書ける
}
}
ES2019
Array.prototype.flat()
/ Array.prototype.flatMap()
メソッド
重要度★★
多階層の配列を任意の階層に減らすこと(フラット化)ができる。
const ar1 = [[1, 2], 3, 4].flat();
console.log(ar1) //=> [1, 2, 3, 4]
const ar2 = [0, 1, 2, [[[3, 4]]]].flat(2);
console.log(ar2) //=> [0, 1, 2, [3, 4]]
const userData = [
{
name: "Taro",
hobby: ["ゲーム", "漫画", "野球"]
},
{
name: "Hana",
hobby: ["映画", "カラオケ"]
},
{
name: "Ken",
hobby: ["ランニング", "サッカー", "旅行"]
}
];
const hobbyList = userData.flatMap(data => data.hobby);
console.log(hobbyList) //=> ["ゲーム", "漫画", "野球", "映画", "カラオケ", "ランニング", "サッカー", "旅行"]
Object.fromEntries()
メソッド
重要度★★
キー・値のペアからオブジェクトを生成する。
ES2017で追加されたentries()
メソッドの逆。
const user = Object.fromEntries([["id", 1], ["name", "Taro"]]);
console.log(user) //=> {id: 1, name: "Taro"}
String.prototype.trimStart()
/String.prototype.trimEnd()
メソッド
重要度★
文字列の先頭または末尾の空白を除去するメソッド。
const name = " Taro ".trimStart();
console.log(name) //=> "Taro "
const lunch = " 寿司 ".trimEnd();
console.log(lunch) //=> " 寿司"
ES2020
オプショナルチェーン演算子
重要度★★★
?.
を使用することで、参照がnullish
(null または undefined)の場合にエラーとなるのではなく、式が短絡されundefined
が返される。
const userData = {
name: 'Taro',
dog: {
name: 'Pochi'
}
};
console.log(userData.name) //=> Taro
console.log(userData.dog.name) //=> Pochi
console.log(userData.cat?.name) //=> undefined
Null合体演算子
重要度★★
??
を使用し、左辺がnullish
(null または undefined)の場合に右の値を返し、それ以外の場合に左の値を返す。
const hero = null ?? 'Taro';
console.log(hero); //=> Taro
const num = 0 ?? 10
console.log(num) //=> 0
動的import
重要度★
通常のimportと違い、Promise
の形でimportすることができるようになったので、使いたいときだけimportすることが可能。
export const name = "Taro"
import("./module.js").then(module => {
console.log(module.name) //=> Taro
})
setTimeout(async () => {
const { name } = await import("./module.js")
console.log(name) //=> Taro
}, 1000)
Promise.allSettled
重要度★
Promise.all
と違い、複数のうちどれか1つがreject
されても他のPromise
は問題なく実行されます。
const promiseList = [
Promise.resolve("ok"),
Promise.resolve("ok"),
Promise.reject("ng"),
Promise.resolve("ok")
]
Promise.allSettled(promiseList).then(
resolveList => {
console.log("resolve")
resolveList.forEach(resolve => console.log(resolve))
},
reject => {
console.log("reject")
console.log(reject)
}
)
// => resolve
// => { status: 'fulfilled', value: 'ok' }
// => { status: 'fulfilled', value: 'ok' }
// => { status: 'rejected', reason: 'ng' }
// => { status: 'fulfilled', value: 'ok' }
BigInt
重要度★
Number
より大きな整数2^53
以上の整数を扱えるオブジェクト。
数値にn
を追加することで使用することができる。
console.log(BigInt(Number.MAX_SAFE_INTEGER) + 2n) // => 9007199254740993
ES2021
Promise.any
重要度★★
複数のPromise
を渡したときに、ひとつでも成功した時点で解決されるPromise
。
const promise1 = xxx;
const promise2 = xxx;
const promise3 = xxx;
Promise.all([promise1, promise2, promise3])
.then(values => {
// 全てのPromiseがfulfillされたときに呼ばれる
})
.catch(error => {
// ひとつでもrejectされたら呼ばれる
});
Promise.any([promise1, promise2, promise3])
.then(first => {
// ひとつでもfulfillされたら呼ばれる
})
.catch(error => {
// 全てのPromiseがrejectされたときに呼ばれる
});
String.prototype.replaceAll
メソッド
重要度★
一致する文字列を全て置換する。
replaceの場合、最初に一致した文字列のみ置換されていた。
// 従来のreplaceの場合
const test = "Taro Hana Ken Taro Hana".replace("Taro", "Jiro")
console.log(test) //=> "Jiro Hana Ken Taro Hana"
// replaceAllの場合
const test2 = "Taro Hana Ken Taro Hana".replaceAll("Taro", "Jiro")
console.log(test2) //=> "Jiro Hana Ken Jiro Hana"
論理+代入演算子
重要度★
論理演算子やnull合体演算子と代入演算子を合わせたもの。
// 論理和代入
a ||= b;
a || (a = b); // ↑と同じ
// 論理積代入
a &&= b;
a && (a = b); // ↑と同じ
// null合体代入
a ??= b;
a ?? (a = b); // ↑と同じ
numeric separator
重要度★
数値セパレータ。数値を_
で区切って表記できる。
100000000 === 100_000_000; // true
ES2022
Top-level await
重要度★★
async関数の外側でawaitを使えるようになった。
export const hoge = await f();
注意点
asyncでない関数の中では今まで通り使用できません。
Object.hasOwn
メソッド
重要度★★
オブジェクト自身が(継承されていない)指定されたプロパティを持っているかどうかを示す真偽値を返す。
hasOwnProperty
のショートハンド。
const user = {name: "Taro"}
// 従来
Object.prototype.hasOwnProperty.call(user, "name");
// hasOwnの場合
Object.hasOwn(user, "name");
.at
重要度★
Array・String・TypedArray
に、指定位置の値を取得するメソッド.at()
が追加された。
従来では-
での指定ができなかった。
// 従来
'abcdef'[1]; //=> b
'abcdef'[-1]; //=> undefined
// .at()の場合
'abcdef'.at(1); //=> b
'abcdef'.at(-1); //=> f
[1, 2, 3].at(1); //=> 2
[1, 2, 3].at(-1); //=> 3
Class privateメソッド
重要度★
Class内のprivateメソッドの追加。
#
を使用して、プライベートクラスメンバーを生成することができる。
class Foo{
#privatemethod() {
return "privatemethod";
}
publicmethod() {
return "publicmethod";
}
}
Class publicフィールド/privateフィールド
重要度★
JSでは、publicフィールドは後から追加できるのだが、明示的に指定できるようになった。
class Foo{
x = 1;
#y = 1;
}
Class 静的フィールド/静的メソッド
重要度★
静的フィールド・メソッドの追加。上記で紹介したprivateフィールドやメソッドにも対応している。
class Foo{
static x = 1;
static #y = 2;
static bar(){}
static #baz(){}
}
ES2023
Array.prototype.findLast()
メソッド
重要度★
配列の末尾から検索できる
const array1 = [5, 12, 50, 130, 44];
const found1 = array1.findLast((element) => element > 45);
const found2 = array1.findLastIndex((element) => element > 45);
console.log(found1); //=> 130
console.log(found2); //=> 3
実務でよく使用される高階関数
使用頻度の高い高階関数7選の紹介。
forEach
重要度★★★
与えられた関数を、配列の各要素に対して一度ずつ実行する。
単純に、配列の全ての要素に対して何かしらの処理をしたい場合に使用する。
const array1 = ['a', 'b', 'c'];
array1.forEach(element => console.log(element));
//=> a
//=> b
//=> c
注意点
forEachは、後に紹介する6つの関数が利用できない場合のみ使用するのが好ましいです。
filter
重要度★★★
与えられた関数によって、trueと評価された要素のみの配列を生成する。
配列の中から特定の要素のみを抜き出したい場合に使用する。
const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => word.length > 6);
console.log(result); //=> ["exuberant", "destruction", "present"]
find
重要度★★★
与えられた関数によって、trueと評価された最初の要素のみを返す。
配列の中から特定の値を取得したい場合に使用する。
const array1 = [5, 12, 8, 130, 44];
const found = array1.find(element => element > 10);
console.log(found); //=> 12
map
重要度★★★
与えられた関数を配列のすべての要素に対して呼び出し、その結果からなる新しい配列を生成する。
配列の中の要素に処理を加え、要素の値を変更したい場合に使用する。
const array1 = [1, 4, 9, 16];
const map1 = array1.map(x => x * 2);
console.log(map1); //=> [2, 8, 18, 32]
reduce
重要度★★★
配列のそれぞれの要素に対して、順番通りに、コールバック関数を呼び出す。その際、直前の要素における計算結果の返値を渡す。
配列の要素全ての和などを求めたい場合に使用する。
const array1 = [1, 2, 3, 4];
const reducer = (previousValue, currentValue) => previousValue + currentValue;
console.log(array1.reduce(reducer)); //=> 10
some
重要度★★
配列のそれぞれの要素に対して、与えられた関数で評価し、1つでもtrue
と評価されたかどうかをbool値
で返す。
配列の中に目的の値
があるかどうか調べるときなどに使用できる。
const array = [1, 2, 3, 4, 5];
const someTest = array.some((element) => element % 2 === 0)
console.log(someTest) //=> true
every
重要度★★
配列のそれぞれの要素に対して、与えられた関数で評価し、全てtrue
と評価されたかどうかをbool値
で返す。
複数の評価値がtrue
になったときに何か処理をしたい場合などに使用できる。
const array = [1, 2, 3, 4, 5];
const everyTest = array.every((element) => element < 10)
console.log(everyTest) //=> true
おわりに
ここまでお読みいただきありがとうございました。
長くなりましたが、以上の知識を覚えておくと、快適にモダンフロント開発ができると思います。
内容はES2015~2022までに追加された仕様のまとめと高階関数の紹介ですが、開発に大きく関わらない部分や、正規表現の仕様など、若干省いているものもあるためご了承ください。
それぞれの項目毎に自分なりにシンプルにまとめたつもりですが、記述ミスや間違えなどありましたら、ご指摘いただけますと幸いです。
参考にさせていただいた記事
ES2015 (ES6)についてのまとめ
ES2015(ES6) 入門
ECMAScript 2016 (ES7) まとめ
ECMAScript 2017 (ES8) まとめ
ECMAScript 2018 (ES9) まとめ
JavaScriptのES2019で追加された新機能まとめ
ES2020の仕様には、こんなのが追加されました!
【JavaScript】ES2021の新機能
【JavaScript】ES2022の新機能