【JS Is Weird】JavaScript構文クイズ 25題

## はじめに
今回は、以下のjsisweird様のサイトの問題を解いて、非常に面白いなと思い復習がてら書いた記事になります。

https://jsisweird.com/

ここから式と選択肢、回答を順に羅列していきますので、よければ正解を予想しながら読み進めてみてください!

### 1 `true + false`

- `"truefalse"`
- `1`
- `NaN`
- `SyntaxError`

<details><summary>回答</summary>
正解は`1`になります。

演算子 + は両辺をプリミティブ型に変換して計算しようとします。

以下MDNより引用
> 一方が文字列の場合、もう一方のオペランドも文字列に変換され、連結されます。_
もし両方が長整数であれば、長整数同士の加算が行われます。一方が長整数で、もう一方が長整数でない場合、TypeError 例外が発生します。
そうでない場合は、両辺が数値へ変換され、数値同士の加算が行われます。

ブール値は数値に型変換されますので、結果としては1になります。

```javascript
Number(true); // -> 1
Number(false); // -> 0
1 + 0; // -> 1
```
</details>


### 2 `[,,,].length`

- `0`
- `3`
- `4`
- `SyntaxError`

<details><summary>回答</summary>
正解は`4`になります。

`[,,,]`は3つの空スロットを持つ配列を出力します。最後のカンマはTrailing_commas(末尾のカンマ)と言われるらしいです。

参考　：https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Trailing_commas

さらに、以下のような意味のわからない例も記載してありました。あまりにも複雑。
```javascript
[,] + [,]; // -> ""
[] + [] === [,] + [,]; // -> true
[,,,] + [,,,]; // -> ",,,,"
([,,,] + [,,,]).length === [,,,,].length; // -> true
```

</details>

### 3 `[1, 2, 3] + [4, 5, 6]`

- `"123456"`
- `"1,2,34,5,6"`
- `"1,2,3,4,5,6"`
- `NaN`

<details><summary>回答</summary>
正解は`"1,2,34,5,6"`になります。

配列は文字列に変換され、連結されます。
参考記事として以下の二つが記載されていました。

https://stackoverflow.com/questions/17977232/php-query-string-url-issue/17977274#17977274

https://2ality.com/2012/01/object-plus-object.html

</details>

### 4 `0.2 + 0.1 === 0.3`

- `true`
- `false`
- `NaN`
- `SyntaxError`


<details><summary>回答</summary>
正解は`false`になります。
こちらは比較的有名な気がしますね。

浮動小数点数を比較する際に起こる問題です。

https://stackoverflow.com/questions/588004/is-floating-point-math-broken

</details>

### 5 `10,2`

- `10.2`
- `10`
- `2`
- `20`

<details><summary>回答</summary>
正解は`2`になります。
カンマ演算子は単に最後のオペランドの値を返すらしいです。

```javascript
10, 2; // -> 2
1, 2, 3, 4; // -> 4
42, "pineapple", true; // -> true

```
</details>


### 6 `!!""`

- `true`
- `false`
- `undefined`
- `SyntaxError`

<details><summary>回答</summary>
正解は`false`になります。

二重否定と呼ばれる記法です。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_NOT#%E4%BA%8C%E9%87%8D%E5%90%A6%E5%AE%9A_!!

複数の否定演算子を連続して使用することで、明示的にあらゆる値を対応する`論理型プリミティブ`に変換することができます。

今回の例で言うと、`""`自体がfalsyな値ですので、その否定の否定で`false`になります。

```javascript
n1 = !!true; // !!truthy は true を返す
n2 = !!{}; // !!truthy は true: *あらゆる*オブジェクトは真値になります...
n3 = !!new Boolean(false); // ... .valueOF() が false の Boolean オブジェクトであっても
n4 = !!false; // !!falsy は false を返す
n5 = !!""; // !!falsy は false を返す
n6 = !!Boolean(false); // !!falsy は false を返す
```
</details>

### 7 `+!![]`

- `true`
- `false`
- `0`
- `1`

<details><summary>回答</summary>
正解は`1`になります。
ここまでの問題の知識で解けますね。
`[]`はオブジェクトなのでtruthyな値です。その二重否定でtrueが取れ、`+true`となります。
+の両辺は数値型に変換されますので、結果`+1`となります

</details>

### 8 `parseInt(0.0000005)`

- `0`
- `1`
- `5`
- `NaN`

<details><summary>回答</summary>
正解は`5`になります。

`parseInt()`は引数を文字列に変換し、次に数字に変換します。0.0000005が文字列に変換されると次のようになります。

`String(0.0000005); // -> "5e-7"`

parseInt関数はその文字列の最初の文字、5だけを返す。となるらしいです。
これはわからなかった...

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/parseInt

</details>

### 9 `true == "true"`

- `true`
- `false`
- `undefined`
- `SyntaxError`

<details><summary>回答</summary>
正解は`false`になります。

==(抽象的な等価比較)は、比較する際に両辺を数値へ変換します。

なので、`1 == NaN`となり、falseになります。

</details>

### 10 `010 - 03`

- `7`
- `5`
- `3`
- `NaN`

<details><summary>回答</summary>
正解は`5`になります。

`010`はJavaScriptによって8進数として扱われます。したがって以下のようになります。
```javascript
010; // -> 8
03; // -> 3
8 - 3; // -> 5
```
</details>

### 11 `"" - - ""`

- `""`
- `0`
- `NaN`
- `SyntaxError`

<details><summary>回答</summary>
正解は`0`になります。
空文字列はどちらも0に変換されますので、`0 - 0`となります。
</details>

### 12 `null + 0`

- `0`
- `"null0"`
- `NaN`
- `TypeError`

<details><summary>回答</summary>
正解は`0`になります。
nullは数値に変換され、falsyな値なので0となります。
結果`0 + 0`となります。
</details>

### 13 `0 / 0`

- `0`
- `Infinity`
- `NaN`
- `SyntaxError`

<details><summary>回答</summary>
正解は`NaN`になります。

0/0という方程式には意味のある数値的な答えはないので、出力は単にNaNとなります。
</details>

### 14 `1 / 0 > 10 ** 1000`

- `true`
- `false`
- `NaN`
- `SyntaxError`

<details><summary>回答</summary>
正解は`false`になります。

以下のような値は`Infinity`となります。
```javascript
1/0; // -> Infinity
10 ** 1000; // -> Infinity
Infinity > Infinity; // -> false
```
また、`10 ** 1000`も`Infinity`となり、結果`false`となるそうです。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Infinity

</details>

### 15 `true++`

- `1`
- `2`
- `NaN`
- `SyntaxError`

<details><summary>回答</summary>
正解は`SyntaxError`になります。
以下のような式は`SyntaxError`になるそうです。

```javascript
true++; // -> SyntaxError
1++; // -> SyntaxError
"x"++; // -> SyntaxError
null++; // -> SyntaxError
undefined++; // -> NaN
$++; // -> NaN
console.log++; // -> NaN
NaN++; // -> NaN
```

しかし、以下の書き方だと有効になるそうです。
```javascript
let _true = true;
_true++;
_true; // -> 2
```
</details>

### 16 `"" - 1`

- `"1"`
- `"-1"`
- `-1`
- `NaN`

<details><summary>回答</summary>
正解は`-1`になります。
加算演算子（+）は数値と文字列の両方に使用されますが、減算演算子（-）は文字列には使用されないため、JavaScriptはこれを数値間の演算と解釈します。

結果`0 - 1`となります。
</details>

### 17 `(null - 0) + "0"`

- `"null0"`
- `"00"`
- `0`
- `NaN`

<details><summary>回答</summary>
正解は`00`になります。
ここまでの知識を使用して解けますね。

`null - 0`はnullが数値に変換されて0、`(0 - 0)`で　0です。
加算演算子のどちらか一方が文字列の場合、両辺文字列として連結されるので`"0" + "0"`となり`"00"`になります。
</details>

### 18 `true + ("true" - 0)`

- `1`
- `2`
- `NaN`
- `SyntaxError`

<details><summary>回答</summary>
正解は`NaN`になります。
ここまでの知識を使用して解ける...と思いきや、"true"は数値型に変換できないので、`NaN`になります。
</details>

### 19 `!5 + !5`

- `0`
- `10`
- `25`
- `NaN`

<details><summary>回答</summary>
正解は`0`になります。

論理NOT演算子（!）は非ブール値をそのブール値の反対に変換します。
5はbool値で表すとtrueなので、その否定でfalseになります。
結果`false + false`になり、`0 + 0`で`0`になります。
</details>

### 20 `[] + []`の結果は何ですか？

- `[]`
- `[ , ]`
- `""`
- `NaN`

<details><summary>回答</summary>
正解は`""`になります。
前述の通り、JavaScriptは配列を文字列に変換します。
結果`"" + ""`となり、文字列なので連結が行われて`""`になります。
</details>

### 21 `1 + 2 + "3"`

- `6`
- `"123"`
- `"33"`
- `NaN`

<details><summary>回答</summary>
正解は`33`になります。

計算は左から右に行われるので、まず`1 + 2`が計算されます。
その次に`3 + "3"`が実行されます。
</details>

### 22 `typeof NaN`

- `"number"`
- `"nan"`
- `"undefined"`
- `"object"`

<details><summary>回答</summary>
正解は`number`になります。
ECMAScriptの仕様書では、NaNはIEEE 754の「数値でない」値である数値値として説明されているそうです。
</details>

### 23 `undefined + false`

- `"undefinedfalse"`
- `0`
- `NaN`
- `SyntaxError`

<details><summary>回答</summary>
正解は`NaN`になります。
`undefined`は数値に変換できません。
しかし、`!!undefined`はfalseとなります。
</details>

### 24 `"" && -0`

- `true`
- `false`
- `""`
- `-0`

<details><summary>回答</summary>
正解は`""`になります。
Reactを使用している人には簡単だったかもしれませんね。
&&演算子は最初の式がtruthyである場合、2番目の式を返します。そうでない場合、最初の式を返します。空の文字列はfalsyであるため、最初のオペランドを返します。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_AND
</details>

### 25 `+!!NaN * "" - - [ , ]`

- `0`
- `"0"`
- `NaN`
- `I give up`

<details><summary>回答</summary>
正解は`0`になります。
今までの問題の総集編のような問題でした。
乗算演算子は、空文字列を数値に等価な0に変換するという仕様があるので0となります。
</details>


## おわりに
最後までお読みいただきありがとうございました！
演算子と型はJSの基礎的な部分ですが、知らない使用も多くまだまだ学ばなければならないと改めて思いました。

その一方、jsisweird様のトップページに以下のような記載があります。

`この構文のほとんどは、おそらく、そして願わくば、日常生活で使用しないものです。`

今回出題されたいくつかの構文は、たとえコードを短くかけるようになっても直感的でなかったり、わかりづらくしてしまうこともあると感じたので使用には注意が必要かもしれません。

## 今回の記事の引用元

https://jsisweird.com/