ES2016以降に追加されたJavaScriptの機能のまとめ

# なぜこの記事を書こうと思ったのか？

「モダンJavaScript」と検索するとES2015解説している記事はよくあるが
ES2016以降をまとめた記事が以外と少ないと感じたので自分用にまとめてみました。
なのでこの記事ではES2015の新機能については書かないです。
ES2017で追加された非同期処理(awaitやPromiseオブジェクト)についても他に解説記事が多く見つかるので書かないです。
追加された全部の機能を書くわけではなくて使えそうだなと思った機能だけ書きます。



## ES2016

### Array.includes
特定の要素が配列に含まれているかどうかを true または false で返します。

```javascript
const array1 = [1, 2, 3];

console.log(array1.includes(2));
// Expected output: true

const pets = ['cat', 'dog', 'bat'];

console.log(pets.includes('cat'));
// Expected output: true

console.log(pets.includes('at'));
// Expected output: false

```

値が含まれているか、いないかをシンプルに書けるようになりました。
似たようなメソッドに「indexOf」や「test」があるがこれらよりも単純に値があるか、ないかを調べる時は「includes」がシンプルで便利です。

### 引用元と参考記事
[MDN Array.prototype.includes()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/includes)

[わくわくBank 「含むか」の判定(配列, 文字列)](https://www.wakuwakubank.com/posts/485-javascript-include-array-string/#index_id)


## ES2017

### Object.keys()とvalues()とentries()
Object.keys()メソッドは、オブジェクトのプロパティを配列で取得します。
Object.values()メソッドは、オブジェクトのプロパティの値を配列で取得します。
Object.entries()メソッドは、オブジェクトのプロパティの組 [key, value]を配列で取得します。

```javascript

const openingHours = {
  wed: {
    open: 12,
    close: 22,
  },
  thu: {
    open: 11,
    close: 23,
  },
  fri: {
    open: 0, // Open 24 hours
    close: 24,
  },
};

//Object.keys()
const properties = Object.keys(openingHours);
console.log(properties); //["wed", "thu", "fri"]という配列

//Object.values()
const values = Object.values(openingHours);
console.log(values);
/*
[
0: {open: 12, close: 22}
1: {open: 11, close: 23}
2: {open: 0, close: 24}
]
*/

//Object.entries()
const entries = Object.entries(openingHours);
console.log(entries);
/*
(3) [Array(2), Array(2), Array(2)]
0: Array(2)
0: "wed"
1: {open: 12, close: 22}
length: 2
__proto__: Array(0)
1: Array(2)
0: "thu"
1: {open: 11, close: 23}
length: 2
__proto__: Array(0)
2: Array(2)
0: "fri"
1: {open: 0, close: 24}
length: 2
__proto__: Array(0)
length: 3
__proto__: Array(0)
*/

```

上記コードのように
Object.keys()は、オブジェクトのキーを配列で取得し、
Object.values()は、オブジェクトのプロパティを配列で取得し、
Object.entries()は、オブジェクトの[key, value] をセットにした配列を取得することができます。

オブジェクトを順番に配列データとして取得出来るので、その後はJavaScriptの標準で提供されているさまざまな配列メソッドが利用出来ます。
配列にしてしまえばデータの扱い方が便利になるのでObject.keys()、Object.values()、Object.entries()を使うだけで配列になるのはありがたいです。
オブジェクトからfor文で取得して配列に加工するという手間が必要なくなるので使い所は多いと思います。


### 引用元と参考記事
[MDN Object.values()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/values)

[devsakaso JavaScriptのObject.keys()とvalues()とentries()メソッド](https://devsakaso.com/javascript-object-keys-values-entries/)


### String.padStart/String.padEnd　(桁埋めのことです)
指定した長さになるように文字列を埋めることが出来ます。

#### 新機能「padStart()」を使用した場合

```javascript
// ランダムな数字を文字列化したもの
let num1 = "15";
let num2 = "4320";
let num3 = "77777";

// 5ケタに合わせる
// padStartを使う
console.log( num1.padStart(5, 0) ); // 00015
console.log( num2.padStart(5, 0) ); // 04320
console.log( num3.padStart(5, 0) ); // 77777

```

#### 以前のやり方 「slice()」を使用した場合

```javascript
// ランダムな数字を文字列化したもの
let num1 = "15";
let num2 = "4320";
let num3 = "77777";

// 5ケタに合わせる
// 一旦0を5ケタ分足して、後ろから5ケタを取得
console.log( ("00000" + num1).slice(-5) ); // 00015
console.log( ("00000" + num2).slice(-5) ); // 04320
console.log( ("00000" + num3).slice(-5) ); // 77777

```

padStart()を使用すると「どの値」「何桁」追加するのか直観的に書けてかなり分かりやすくなりました。
以前のslice()を使用したやり方では一旦0を5ケタ分足して、後ろから5ケタを取得するという手間がかかっているので面倒でした。
桁を合わせたい場面は意外と多いと思うのでシンプルに書けるpadStart()の登場はありがたいと思います。


### 引用元と参考記事
[Hatoblog JavaScriptでゼロパディングする（文字列を埋める）メソッド【padStart、padEnd】](https://hatoblog.net/js-methods-padstart-padend/)


## ES2018

### オブジェクトのRest/Spread

```javascript
let string = 'defg';

let array = ['a', 'b', 'c', ...string];

console.log(array);
// ["a", "b", "c", "d", "e", "f", "g"]

```
「Spread」は「...」(ドット3つ)を使用した配列の展開です。
これを使用するだけで配列の中に値を追加するのが簡単に出来ます。
ES2015で配列にスプレッド構文を使用することができましたが、ES2018ではオブジェクトにも使用できるようになりました。

### 引用元と参考記事
[【JavaScriptの応用】spreadオペレーターとrestパラメーター](https://tcd-theme.com/2021/10/javascript-spreadoperator-restoperator.html)


## ES2019

### String.prototype.trimStart()または.trimEnd()

```javascript
const greeting = '   Hello world!   ';

console.log(greeting);
// Expected output: "   Hello world!   ";

console.log(greeting.trimStart());
// Expected output: "Hello world!   ";
```

trimStart()は先頭の空白を削除してくれます。
trimEnd()は末尾の空白を削除です。
地味な機能ですが空白を簡単に削除してくれるので便利です。


### 引用元と参考記事
[MDN String.prototype.trimStart()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/trimStart)


### Array.prototype.flat()

```javascript
const arr1 = [0, 1, 2, [3, 4]];

console.log(arr1.flat());
// Expected output: Array [0, 1, 2, 3, 4]

const arr2 = [0, 1, 2, [[[3, 4]]]];

console.log(arr2.flat(2));
// Expected output: Array [0, 1, 2, Array [3, 4]]

//今回の場合は引数に3を入れればすべて平坦化される。
//配列の[]をどのくらい平坦化するか引数で調整出来るので細かい調整も出来て便利。
console.log(arr2.flat(3));
//Expected output: Array [0, 1, 2, 3, 4]
```

MDNにはflat() メソッドは、すべてのサブ配列の要素を指定した深さで再帰的に結合した新しい配列を生成します。
と書かれていてよく意味が分かりませでしたので調べてみると、
配列内の配列を平坦に整えてさらに新しい配列を生成出来る機能のようです。
引数で深さを受け取り、何段階まで平坦化するのか指定できます。
「const arr2」は最大の深さが3だったので3を引数に入れればすべて平坦になりました。
配列を取得した時に深さがバラバラで揃えるのが面倒だったのがこの機能で簡単に出来ます。
配列操作としてはとてもありがたい機能ですね。


### 引用元と参考記事
[MDN Array.prototype.flat()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/flat)


## ES2020

### Null合体演算子(MDNでは「Null 合体代入 (??=)」と紹介されています。)

Null合体演算子は、nullか判断して、nullだった場合は??の右側の値を返します。

```javascript
let fruits = 'banana'
let result = fruits ?? 'nullでした'
console.log(result)
// Expected output: 'banana'

```

これだけだと何の役に立つかよく分からないと思いますが、次に紹介する
「オプショナルチェーン(Optional Chaining)」と組み合わせると効果的です。


### 引用元と参考記事
[MDN Null 合体代入 (??=)](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_assignment)
[コードライク JavaScriptのNull合体演算子(”??”)の使い方！](https://codelikes.com/javascript-null-coalescing-operator/)


### オプショナルチェーン(Optional Chaining)

オプショナルチェーン演算子はオブジェクトのプロパティに演算子(.?)を使ってアクセスします。
オプショナルチェーン演算子を使うことで、プロパティの値がない場合にundefinedを返します。

```javascript
const user = {
  age: 30,
  likes: {
    food: 'sushi'
  }
};

let result = user.address?.prefecture;
console.log(result); // undefined

result = user.likes?.food;
console.log(result); // sushi

```
最初にuserオブジェクトを作成しています。

次の処理で、userオブジェクトのaddressプロパティにアクセスして、さらに配下のprefectureプロパティの値を取ってこようとしています。
このときにオプショナルチェーン演算子(.?)を使うことで、値がない場合にはundefinedを返すようになります。
console.logで値を出力すると、undefinedになっていることがわかります。

次の行で、値が設定されているプロパティにオプショナルチェーン演算子をつけてアクセスしています。
この「user.likes?.food」には値が設定されているので、普通に値が返ってきます。
出力すると、格納されている「sushi」が返ってくることが確認できます。

##### もしもオプショナルチェーン演算子を使わなかったらエラーになる

```javascript
const user = {
  age: 30,
  likes: {
    food: 'sushi'
  }
};

let result = user.address.prefecture;
console.log(result); // 出力されずエラー

```

オプショナルチェーン演算子を使うことで、prefectureプロパティを読み取る前に、addressプロパティが存在するか確認してくれます。

そして、存在しなかった場合は、その時点でundefinedを返してくれます。
今回の場合だと、 このように「user.address?.prefecture」とすることで、prefectureプロパティにアクセスする前にaddressプロパティを調べてundefinedを返してくれています。

##### プロパティの値が存在しなかった場合の「初期値」をNull合体演算子と組み合わせることで設定出来る

```javascript
const user = {
  age: 30,
  likes: {
    food: 'sushi'
  }
};

let result = user.address?.prefecture ?? "福岡県";
console.log(result); // 福岡県

```

userオブジェクトのaddressのprefectureプロパティにアクセスしようとしていますが存在しません。
存在しないのでundefinedになり、Null合体演算子(??)で値がないと判定されて、「福岡県」が返ってきます。

このように使うことで値がない場合エラーが起きなくなります。
初期値を設定することも出来るので活躍する場面が多いと思います。
特に便利だなと思った点は1行で書けることです。
値がある場合とない場合をif文で分けて処理する必要がありません。
コードがかなりスッキリします。
1行で書けるのでReactでよく使われる印象があります。



### 引用元と参考記事
[MDN オプショナルチェーン (?.)](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Optional_chaining)
[コードライク JavaScriptのオプショナルチェーン演算子の使い方！](https://codelikes.com/javascript-optional-chaining/)