【解説編】モダンJavaScript構文ビンゴ 〜あなたはモダンなJavaScriptをどこまで理解できていますか？〜

# モダンJavaScript構文ビンゴ

IE11お疲れ様でした記念！

皆様、モダンJavaScriptの時代がようやくやってきました。

というわけでまずは、こちらの「モダンJavaScript構文ビンゴ」を無心でやってくださいませ。
パッとみて「理解できる」と思ったらチェックできます。

https://mekepon.com/bingo/CossiLrrvvf0VkIfXZMY

どうでしたか？

割とできました？
それとも全然チェックできませんでした？

個人的には、これ1つでもチェックできる人と一緒に仕事したいです。

というわけで、回答編というか解説編です。


# [...items]

```javascript
...items
```

これは「スプレッド構文」と言われるもので、itemsの中身が```[1, 2, 3]```だった場合に、```...items```は```1, 2, 3```に置き換えられます。
これはどういうことかというと、つまり、

```javascript
const newItems = [...items];
```

が、

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

として評価されるということです。

これはとても便利で、例えば次のような関数があったとき、スプレッド構文で引数を指定できます。

```javascript
function myFunction(x, y, z) {
    return x + y + z;
}

const items = [1, 2, 3];
const result = myFunction(...items); // 6
```

以前はapplyメソッドを使っていたので、だいぶすっきりします。

```javascript:applyを使った以前の書き方
const result = myFunction.apply(null, items);
```

スプレッド構文を使って配列の結合や要素の追加ができます。

```javascript
const items = [1, 2, 3];
const newItems = [0, ...items, 4, 5]; // [0, 1, 2, 3, 4, 5]
const newItems2 = [...newItems, 0, ...items]; // [0, 1, 2, 3, 4, 5, 0, 1, 2, 3]
```

尚、この時に展開される要素の値は元の要素の複製です。しかし、要素が構造を持っている場合、子要素までは複製されないので注意が必要です。
言い換えると、変数自体は複製されますが、変数の参照先までは複製されません。

つまり、こういうことです。

```javascript
const items = [ 5, { num1: 1 } ];
const newItems = [...items];

newItems[0] = 6;
console.log(items[0]); // 5

newItems[1].num1 = 2;
console.log(items[1].num1); // 2
```

# {...org, c:3}

せっかくなので続けてこちらを。これもスプレッド構文の一つで、こちらはオブジェクト用のスプレッド構文です。

似たような説明を書くのが面倒なので、MDNより引用します。

```javascript
let obj1 = { foo: 'bar', x: 42 };
let obj2 = { foo: 'baz', y: 13 };

let clonedObj = { ...obj1 };
// Object { foo: "bar", x: 42 }

let mergedObj = { ...obj1, ...obj2 };
// Object { foo: "baz", x: 42, y: 13 }
```

同じプロパティ名は上書きしてくれます。

尚、Object.assign()と似たような動きに見えますが、Objet.assignはコピー先のオブジェクトのセッターを起動するのに対して、スプレッド構文ではセッターを起動しない事に注意が必要です。

また、複製されるのは配列の時と同じく変数自体であり、その参照先は複製されません。

```javascript
const obj1 = {
    child1: {
        childnum : 5  
    },
    num1: 5
};

const obj2 = { ...obj1 };

obj2.num1 = 6;
console.log(obj1.num1); // 5

obj2.child1.childnum = 6;
console.log(obj1.child1.childnum); // 6

console.log(obj1.child1 === obj2.child1); // true
```

# [a,b] = arr

続けて、分割代入です。こちらは最近、react等でも頻繁に用いられる為、慣れている人もいるかもしれません。

この書き方をすると、配列の一部を個別の変数に割り当てて取り出す事ができます。

MDNのサンプルが分かりやすいのでそのまま引用します。

```javascript
const foo = ['one', 'two', 'three'];

const [red, yellow, green] = foo;
console.log(red); // "one"
console.log(yellow); // "two"
console.log(green); // "three"
```

もし、受け取る側の変数リストがコピー元より多い場合はどうなるでしょうか。
これは単にundefinedになります。

```javascript
const foo = ['one', 'two'];

const [red, yellow, green, blue] = foo;
console.log(red); // "one"
console.log(yellow); // "two"
console.log(green); // undefined
console.log(blue);  //undefined
```

undefinedではなく、規定値を指定することもできます。

```javascript
let a, b;

[a=5, b=7] = [1];
console.log(a); // 1
console.log(b); // 7
```

逆に受け取る側の方が少ない場合、単に捨てられます。
しかし、「残り全部を配列で受け取りたい」場合もあるでしょう。
その時は、スプレッド構文を使うことができます。

```javascript
const [a, ...b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // [2, 3]
```

途中をカンマで飛ばして受け取ることもできます。

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

const [a,,b] = items;
console.log(a); // 1
console.log(b); // 3
```

関数の戻り値が配列の場合に、それを個別の変数で受け取ることができて便利です。

```javascript
function useState( value = null )
{
  return [ 
    () => value, 
    v => { value = v } 
  ]
}

const [getA, setA] = useState(10);
console.log(getA()); // 10
setA(20);
console.log(getA()); // 20

const [getB, setB] = useState(1);
console.log(getB()); // 1
setB(2);
console.log(getB()); // 2
```

また、配列と同様にオブジェクトも分割代入できます。

```javascript
const user = {
    id: 42,
    isVerified: true
};

const {id, isVerified} = user;

console.log(id); // 42
console.log(isVerified); // true
```

宣言と同時に代入するのではなく、後から代入する場合は、中括弧をブロックだと認識されないよう、丸括弧で囲う必要があるので注意してください。

```javascript
let a, b;

({a, b} = {a: 1, b: 2});
```

別名のプロパティへの代入も可能です。

```javascript
const o = {p: 42, q: true};
const {p: foo, q: bar} = o;

console.log(foo); // 42
console.log(bar); // true
```

便利ですね。（この辺はどれもMDNからの引用です）


# r=>r.json()

すいません、これはちょっと書き方が悪かったかもしれません。
もう少しシンプルな例を挙げると、次のようなものです。

```javascript
r => r + 1
```

そう、ラムダ式と言われるものです。
これは、次のものとほぼ同じです。

```javascript
function(r){
    return r + 1;
}
```

ですので、次のように変数や定数に代入しておくと、関数として呼び出す事ができます。

```javascript
const myFunc = (r => r + 1);

console.log(myFunc(10)); // 11
```

Arrayにはmapやreduceなどの便利な高階関数がありますが、これらは引数に関数を取ります。
そのような場合に、いちいち次のように書かず

```javascript
const items = [{num1 : 1}, {num1: 2}, {num1: 3}];
const result = items.map(function(item){ return item.num1 });
console.log(result); // [1, 2, 3]
```

次のように書けます。

```javascript
const items = [{num1 : 1}, {num1: 2}, {num1: 3}];
const result = items.map(items => item.num1);
console.log(result); // [1, 2, 3]
```

returnを省略できますし、冗長な「function」定義も不要ですので、見た目に「何をさせたいか」をすっきりと記述できます。

functionと何が違うのかですが、thisの扱いが異なります。
functionでは、thisは「**その関数が所属するオブジェクト**」になります。
しかしラムダ式では、「**そのラムダ式が定義された時点でのthis**」を参照します。

この話は少し複雑な話になりますので、興味のある方は調べてみて下さい。

よくわからない人は、「**ラムダ式を使う場合、thisは常にその外側のthisを指しているので安心して使えるけど、匿名functionの場合、外側のthisは呼び出されるタイミングによっては違うthisかもしれない**」ぐらいに覚えておくと良いでしょう。決してラムダ式のthisの方が優れているというわけではなく、functionのthisの解決方法が必要な場面もあります。


# obj?.getX()

```?.```はオプショナルチェーン演算子といって、その直前のオブジェクトの参照が```null```又は```undefined```の場合に、エラーにならずにそこで短絡され、```undefined```が返ります。

なので、これまで次のように書いていたのを、

```javascript
let result;
if ( obj ) {
    result = obj.getX();
}
```

次のように書けます。

```javascript
const result = obj?.getX();
```

これがもし深いところにあるオブジェクトだと、この素晴らしさに感動することでしょう。

```javascript
const result = obj.first?.second?.third;
```

ところで、「関数が存在する時には呼び出す」という時には、次のように書けます。
これはいきなり見るとぎょっとしますが、便利なものです。

```javascript
const result = obj.methodA?.();
```

methodAが存在しない場合、resultにはundefinedが入り、例外は発生しません。

# a ?? 0

この勢いでこちらも行ってみましょう。
これは「null合体演算子」と呼ばれるもので、左辺がnull又はundefinedの時、右辺を返します。
nullでもundefinedでもなければ、左辺そのものを返します。

つまり、nullishの時の規定値を指定できるわけです。

次のように書けばいいじゃないかと思われるかもしれません。

```javascript
const result = a || 0;
```

しかし、もし aが''で、それは有効値として扱いたい場合であっても、||の左辺は論理値として評価され、''はfalseとして評価される為、0が返ってしまいます。

```javascript
const result = a ?? 0;
```

上記の書き方ならば、aがnull又はundefinedの時だけ、右辺が返ります。
より安全なコードと言えるでしょう。

また、null合体演算子は前述のオプショナルチェーン演算子と組み合わせることで、よりシンプルな記述が可能となります。

```javascript
const result = items.map(item => item.numA); /// itemsがnullの時例外が発生
```

上記の処理において、itemsがnullだった場合、例外が発生してしまいます。

itemsがnullの時はresultに空の配列が返るように書きたい時、null合体演算子とオプショナルチェーン演算子を組み合わせて次のように書く事ができます。

```javascript
const result = items?.map(item => item.numA) ?? [];
```

上記を見て、「なんだか呪文のようだ」と思われるでしょうか。
しかし、null合体演算子もオプショナルチェーン演算子も使わずに上記を書こうとしたら、どれだけ長ったらしいコードになるか想像してみると、「これで良い」と思えるようになるかもしれません。

もちろん、上記の書き方に慣れていない人の為に敢えて冗長な書き方をするという選択肢もあると思います。


# \`${year}年\`

この書き方は、テンプレートリテラルと呼ばれる書き方です。シングルクォートではなくバッククォートで囲うことにご注意ください。

文字列の中に変数を```${変数名}```の形式で埋め込むことができます。

これまで次のように書いていた場合、

```javascript
const result = d.getFullYear() + '年' + d.getMonth() + '月' + d.getDate() + '日';
```

次のように書けます。

```javascript
const d = new Date();
const result = `${d.getFullYear()}年${d.getMonth()}月${d.getDate()}日`;
console.log(result);  // "2022年6月5日"
```

この例だと良さが分からないかもしれませんが、改行含みのHTMLテキストなどを定義する時等、便利に記述できます。


# async/await

fetch関数のようなPromiseを返す非同期関数の呼び出しの際に、then()を使わずにawaitを使って「同期的に見える」書き方ができます。

```javascript:then()を使った従来の記述
fetch(url)
	.then( response => response.json() )
	.then( data => {
		// dataの処理
		console.log(data.Message);
	});
```

```javascript:awaitを使った同期的に見える記述
const response = await fetch(url);
const data = await response.json();
// dataの処理
console.log(data.Mesage);
```

詳しくは以前書いた記事などを参考にどうぞ。

https://qiita.com/jun1s/items/ecf6965398e00b246249

https://qiita.com/jun1s/items/4ec151b1c2562f6b0f26

https://qiita.com/jun1s/items/d0a234700a14bf910065


# yield i

最後に控えるは、ジェネレータ関数です。

以前書いた記事から抜粋します。

[ジェネレータ](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Iterators_and_Generators)とは、イテレータを生成する為の仕組みです。
イテレータとは、配列のような繰り返し構造を持つデータにアクセスする為の仕組みです。

ジェネレータは、関数名の後ろに`*`を付け、内部で`yield`を実行することで定義することができます。

```javascript
function* mygenerator(){
  let count = 0;
  count++;
  yield count;
  count++;
  yield count;
  count++;
  yield count;
}
```

このmygeneratorは、次のように使います。

```javascript
for (const i of mygenerator()) {
    console.log(i);
}
```

ログには次のように出力されます。

```
1
2
3
```

これは、次の処理と同じ結果です。


```javascript

for (const i of [1, 2, 3]) {
    console.log(i);
}
```

ジェネレータがどのように働くか、理解できたでしょうか。

mygeneratorの中でyieldが呼ばれると、mygeneratorは現在のcountを返して一旦処理を停止します。そして、forループから次の値を請求されると、停止した所から処理を再開し、また次のyieldで、値を返します。

mygeneratorの最後まで実行したら、ループ（イテレーション）を終了します。

このような機能を「**継続**」と呼び、ジェネレータをイテレーション（配列データの繰り返し処理）の為ではなく、コルーチン（処理を一時的に止めたり再開したりする機能）として利用することも可能です。

# まとめ

以上、モダンJavaScriptビンゴの回答編でした。

上記の構文は、最新のメジャーなブラウザで利用可能です。
そう、Chromeでも、Edgeでも、Firefoxでも、Operaでも、Safariでも、AndroidでもiOSでも、です。
それらのブラウザであっても、もちろん古いバージョンだと動かなかったりしますが…。

ターゲットブラウザの確認はしっかり行った上で、ぜひ使い倒していきましょう。