【ES6】FizzBuzz問題のJavaScript最短コードを解説します

## FizzBuzz問題とは

```:問題
1から100までの数をプリントするプログラムを書け。
ただし3の倍数のときは数の代わりに｢Fizz｣、5の倍数のときは｢Buzz｣とプリントし、
3と5の両方の倍数のときには｢FizzBuzz｣とプリントすること。
```

上記問題をFizzBuzz問題と言い、エンジニアの中では有名な問題らしいです。（恥ずかしながらつい最近まで知りませんでした..）
問題自体は、if文を使って一つずつ条件を書き、for文を使って1から100までループさせることで比較的簡単に解くことができます。

## FizzBuzzコードゴルフ

しかし、これを可能な限り少ないコードで書こうとすると、とたんに難しくなります。
（問題の条件を満たすプログラムをできるだけ短い文字数で実現する競技を**Code Golf**と呼びます。）

長いこと考えた末、、

```js:JS
for(i=1;i<101;i++){console.log(i%15?i%3?i%5?i:'Buzz':'Fizz':'FizzBuzz')}
```
条件演算子を駆使して、なんとか72文字の解までたどり着きました。

が、

ネットの海に潜ってJavaScriptの最短コードを探したところ、なんと**62文字**の最強の解が見つかりました。
それがこれ↓

```js:JS
for(i=0;++i<101;console.log(i%5?x||i:x+'Buzz'))x=i%3?'':'Fizz'
```


「なんだこれ？、意味わからん..」と思い、コードの中身を調べていたところ
そのあまりに綺麗なロジックに感動してしまいました。。

以下その感動を伝えたい解説記事です。

**※最短解引用元**
[ES2015時代のFizzBuzzに挑戦する - Qiita](https://qiita.com/butchi_y/items/59d45e8212643b43cba4)
[FizzBuzz JavaScript solution · GitHub](https://gist.github.com/jaysonrowe/1592432)

## コード解説
ポイントは3点。
**（1）for文の{ }を省略**
**（2）基礎を踏まえた繰り返しの定義**
**（3）神の条件分岐ロジック**

### （1）for文の{ }を省略
通常for文を書くとき、

```js
for () {
//処理の文
}
```
のように書きますが、「処理の文」が1つのときは文を囲む`{ }`を省略することができます。
つまり、

```js
for ()//処理の文
```
のように書くことができ、
FizzBuzz最短解ではこのショートハンドを使用しています。

```js
// 最短解
for(i=0;++i<101;console.log(i%5?x||i:x+'Buzz'))x=i%3?'':'Fizz'


// for文の{}を省略せずに書いた場合
for(i=0;++i<101;console.log(i%5?x||i:x+'Buzz')) {
  x = i%3 ? '' : 'Fizz';
}
```
でも正直まだ全然わかんない..:innocent:


### （2）基礎を踏まえた繰り返しの定義
最短解をよく見てみると、for文の`( )`の中に`console.log()`が記述されていることが分かります。

```js:FizzBuzz解のfor文条件式
for(i=0; ++i<101; console.log(i%5?x||i:x+'Buzz'))
```


ここでJavaScriptの**for文の定義**を振り返ってみましょう。

```js:for文の定義
for ([initialization]; [condition]; [final-expression]) statement
```
第1引数の`initialization`は**変数宣言**であり、たいていはカウンタ変数を初期化するために使われます。
FizzBuzz解でも`i = 0;`とループの初期値を定義しています。

第2引数の`condition`は**ループの各反復の前に評価される式**です。
この式が**true**に評価された場合のみ、その後の`statement`が実行されます。
FizzBuzz解では`++i<101;`という定義になっていますが、
これは`i=i+1`が101より小さいときに、式が**true**となりループが実行されるということです。
![スクリーンショット 2020-01-01 21.38.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321338/fd76580f-04f5-bab5-fefa-f08998eb404f.png)


第3引数の`final-expression`は**ループの各反復の終わりに評価される式**です。
FizzBuzz解ではそこに`console.log()`を記述しているため、for文の各反復における処理の文が実行された後（反復の終わり）に、テキストが表示されるようになっています。

ここまでの内容を要約すると、

- **各反復の初めに`i=i+1`が実行され（iの初期値は0）、その数が101より小さい時にfor文の処理が実行される。**
- **各反復でfor文の処理が実行された後に、`console.log()`が実行される。**

となり、
さらにコード形式でまとめると、

```js
// for文の定義
for ('①変数定義';
     '②ループの各反復の前に評価される式';
     '③ループの各反復の終わりに評価される式')
    {'②がtrueの時に実行される処理'}

// FizzBuzz最短解にあてはめる
for (i=0;
     ++i<101; // i=i+1が101より小さい時、つまりi+1が1〜100の時にループが実行される
     console.log(i%5?x||i:x+'Buzz')) // よってconsole.log()が100回実行される
    { x = i%3 ? '' : 'Fizz'; }
```

ということになります。
だいぶ見えてきたけど、まだ表示されるテキスト部分が分からんぞ？:thinking_face:


### （3）神の条件分岐ロジック
#### (3)-1 反復処理の内容
次にFizzBuzz最短解において、for文で反復実行される処理の内容を見ていきます。

```js:FizzBuzz解の反復処理の内容
x = i%3 ? '' : 'Fizz';
```
この文はif文のショートハンドである**条件演算子**を使用しており、

```js:条件演算子を使った条件分岐
'条件式' ？ 'trueの場合の処理' : 'falseの場合の処理';
```
`i%3`が**true**の時は`x=''`、**false**の時は`x='Fizz'`となるよう`変数x`を定義しています。


**補足1：%演算子**
割り算の余りを求めることができる。`i%3`はiを3で割った余り。
ある整数を3で割って余りが0ならその数は3の倍数であると言える。

**補足2：JavaScriptのtrue/false**
`0`はboolean型で**false**の初期値を持つ。他にも`null`や`undefined`、 `''（空文字）`なども**false**となる。
逆にその値が`undefined`や`null`でないオブジェクトは、条件文に通されると全て**true**に評価される。


今回の条件分岐をif文で書くと、

```js:if文による条件分岐の書き換え
if ( i%3 ) {
  x = '';     // iが3の倍数ではないとき
} else {
  x = 'Fizz'  // iが3の倍数のとき
}
```
こうなり、
また表にまとめると、
![スクリーンショット 2020-01-01 18.00.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321338/26c94d54-e288-98fc-4804-ffb3fc1809ae.png)
こうなります。

#### (3)-2 console.log()で表示するテキスト
いよいよ最後！
実際に`console.log()`で表示されるテキストを見てみます。

```js:FizzBuzz解において各反復後に実行される処理
console.log(i%5?x||i:x+'Buzz')
```
これを半角スペースを入れて少し分かりやすく書くと、

```js
console.log( i%5 ? x||i : x+'Buzz')
```
条件演算子を使った**(3)-1**と同様の条件分岐であることが分かり、
`i%5`が**true**の時は`x||i`を、**false**の時は`x+'Buzz'`を表示するよう定義されていることが理解できます。

これを表でまとめると、
![スクリーンショット 2020-01-01 18.32.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321338/353d4d94-5b09-687a-63a8-937c4deff62d.png)
こうなり、
さらに**(3)-1**で解説した`x`の値と合わせてまとめたものが以下の表になります。
![スクリーンショット 2020-01-01 22.36.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321338/35a21621-d960-005b-5acf-6b2e3c497aeb.png)


注目すべきは、`x||i`の部分。
**論理演算子**である`||`は、`x`が**true**の場合は`x`の値をそのまま返し、**false**の場合は`i`を返します。
これによって、`i`が3の倍数の時は`'Fizz'`を表示し、そうでない時は1から100の数字である`i`をそのまま表示できるようになっています。

4つの場合分けパターンに合わせた、神がかった条件定義はまさに感動モノ..

## まとめ
解説は以上です！
ここまでの内容を理解できていれば、FizzBuzz最短解のコードロジックも読み取れるはず！

```js:FizzBuzz最短解
for(i=0;++i<101;console.log(i%5?x||i:x+'Buzz'))x=i%3?'':'Fizz'
```

改めて見ても.. これ考えた人天才だ....:sunglasses:

## 参考にしたサイト
[for - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/for)
[条件 (三項) 演算子 - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Conditional_Operator)
[代入演算子 - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Remainder_assignment)
[論理演算子 - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_Operators)
[Boolean - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Boolean)
[JavaScript ショートコードテクニック集（ES6含む） - Qiita](https://qiita.com/ichimonji_haji/items/f602f6c437be9e7daa88#%E3%83%96%E3%83%AC%E3%83%BC%E3%82%B9%E3%82%92%E7%9C%81%E7%95%A5%E3%81%99%E3%82%8B)