くそったれJavaScript

以下は[What the f*ck JavaScript?](https://github.com/denysdovhan/wtfjs)というリポジトリの日本語訳です。


# What the f*ck JavaScript?

JavaScriptは素晴らしい言語です。
単純な構文、大きなエコシステム、そして最も重要なところはコミュニティです。

同時に、JavaScriptは非常にトリッキーで面倒な言語でもあります。
幾つかの仕様は我々の仕事を地獄に変え、他の幾つかは笑える仕様です。

WTFJSの大元のアイデアは[Brian Leroux](https://twitter.com/brianleroux)によるものです。
以下のリストは2012年のdotJSにおける彼のトーク、[WTFJS](https://www.youtube.com/watch?v=et8xNAc2ic8)に触発されています。

# Node Packaged Manuscript

以下の内容はnpmでインストールできます。

```
$ npm install -g wtfjs
```

`wtfjs`コマンドで読めるようになるはずです。
駄目だったらここで読みましょう。

# Table of Contents

## Motivation

```
面白半分だ。
```

[Just for Fun: The Story of an Accidental Revolutionary](https://en.wikipedia.org/wiki/Just_for_Fun), Linus Torvalds

このリストの主な目的は、バグった実例を収集し、可能であればどうしてそうなっているのかを解説することです。
これまで知らなかったことを学ぶのは楽しいでしょう。

初心者は、これらを通じてJavaScriptをより深く理解することができます。
これらを見ているときっと仕様書を読みたくなることでしょう。

プロの開発者であれば、JavaScriptの持つ罠や予期せぬ挙動の参考資料として役立ててくれると思います。

いずれにせよ、以下を読んでみてください。
おそらく新しい発見があることでしょう。

## Notation

`// ->`は式の結果を表します。

```javascript
	1 + 1 // -> 2
```

`// >`はconsole.logもしくはその他の出力内容を表します。

```javascript
	console.log('hello, world!') // > hello, world!
```

`//`は解説用の単なるコメントです。

```javascript
	// Assigning a function to foo constant
	const foo = function () {}
```

## Examples

### [] is equal ![]

ArrayはArrayとイコールではない。

```javascript
	[] == ![] // -> true
```

[12.5.9 Logical NOT Operator (!)](https://www.ecma-international.org/ecma-262/#sec-logical-not-operator)
[7.2.13 Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison)

### true is false

trueはfalseだった。

```javascript
	!!'false' ==  !!'true'  // -> true
	!!'false' === !!'true' // -> true
```

順番に考えるとわかりやすい。

```javascript
	// trueは数値扱いされると1になる
	true == 'true'    // -> false
	false == 'false'  // -> false

	// 'false'は空文字ではないので数値扱いされると1になる
	!!'false' // -> true
	!!'true'  // -> true
```

[7.2.13 Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison)

### baNaNa

バナナ

```javascript
	'b' + 'a' + + 'a' + 'a'
```

使い古されたジョークのリバイバルで、オリジナルは以下だ。

```javascript
	'foo' + + 'bar' // -> 'fooNaN'
```

式が`'foo' + (+'bar')`と解釈され、'bar'は数値ではないので'NaN'という文字列になる。
[12.8.3 The Addition Operator (+)](https://www.ecma-international.org/ecma-262/#sec-addition-operator-plus)
[12.5.6 Unary + Operator](https://www.ecma-international.org/ecma-262/#sec-unary-plus-operator)

### NaN is not a NaN

NaNはNaNではない。

```javascript
	NaN === NaN // -> false
```

これは仕様で厳密に決められている。

```text
 1. If Type(x) is different from Type(y), return false.
 2. If Type(x) is Number, then
   i. If x is NaN, return false.
   ii. If y is NaN, return false.
   iii. ………
```

[7.2.14 Strict Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-strict-equality-comparison)

IEEEのNaNの仕様に従っている。


```text
Four mutually exclusive relations are possible: less than, equal, greater than, and unordered. The last case arises when at least one operand is NaN. Every NaN shall compare unordered with everything, including itself.
```

[What is the rationale for all comparisons returning false for IEEE754 NaN values?](https://stackoverflow.com/questions/1565164/1573715#1573715)

### It's a fail

信じられないかもしれないが、答えは'fail'だ。

```javascript
	(![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]
	// -> 'fail'
```

以下のパターンが頻出することに気がつくだろう。

```javascript
	(![]+[]) // -> 'false'
	![]      // -> false
```

`false`に`[]`を加算しようとしているため、右オペランドはstringに変換される。

```javascript
	(![]+[].toString()) // 'false'
```

文字列に配列アクセスすると該当番目の文字が取得できる。

```javascript
	'false'[0] // -> 'f'
```

残りも同じ構造だが、`i`の取って来かたは少しトリッキーだ。
文字列'falseundefined'を作って、その10番目を取得している。

### [] is truthy, but not true

`[]`はtrueっぽいけどtrueではない。

```javascript
	!![]       // -> true
	[] == true // -> false
```

ECMA-262で決められている仕様である。
[12.5.9 Logical NOT Operator (!)](https://www.ecma-international.org/ecma-262/#sec-logical-not-operator)
[7.2.13 Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison)

### null is falsy, but not false

`null`はfalseっぽいけどfalseではない。

```javascript
	!!null        // -> false
	null == false // -> false
```

ところが0や''はfalseとイコールになる。

```javascript
	0 == false  // -> true
	'' == false // -> true
```

これもECMA-262の仕様。
[7.2.13 Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison)

### document.all is an object, but it's undefined

document.allは配列のようなobjectであり、DOMノードへのアクセスを提供するが、`typeof`には何故か`undefined`を返す。


```javascript
	document.all instanceof Object // -> true
	typeof document.all            // -> 'undefined'
```

しかし`undefined`とイコールではない。

```javascript
	document.all === undefined // -> false
	document.all === null // -> false
```

緩やかな比較ではイコールになる。

```javascript
	document.all == null // -> true
```

`document.all`は主に古いバージョンのIEで使用されていたDOMへのアクセス方法で、標準仕様になったことはないが、古いJavaScriptコードではよく使用されていた。
`getElementById`等の新しいAPI標準仕様が普及したのち、この`document.all`の取り扱いについて決める必要があった。
JavaScriptの仕様には反していたのだが、広く使用されていたためAPI自体は維持することにした。
===にfalseを返し、==にtrueを返すのは、[明示された例外事項](https://html.spec.whatwg.org/multipage/obsolete.html#dom-document-all)である。

### Minimal value is greater than zero

最小の数値は0より大きい。

```javascript
	Number.MIN_VALUE > 0 // -> true
```

`Number.MIN_VALUE`の値は`5e-324`であり、これは0より大きい最小の値である。
浮動小数で表せる最高の解像度を表している。

いわゆる最小値は`Number.NEGATIVE_INFINITY`として定義されているが、これは厳密には数値ではない。

[20.1.2.9 Number.MIN_VALUE](https://www.ecma-international.org/ecma-262/#sec-number.min_value)

### function is not function

忌々しいundefinedが関数でないことは皆知っているが、では以下は？

```javascript
	// nullをextendsする
	class Foo extends null {}
	// -> [Function: Foo]

	new Foo instanceof null
	// > TypeError: function is not a function
```

これは仕様ではないから、いずれ修正されるだろう。

### Adding arrays

2個の配列を加算したい。

```javascript
	[1, 2, 3] + [4, 5, 6]  // -> '1,2,34,5,6'
```

文字列連結になってしまう。

```javascript
	[1, 2, 3] + [4, 5, 6]
	// toString()が呼ばれる
	[1, 2, 3].toString() + [4, 5, 6].toString()
	// 結合
	'1,2,3' + '4,5,6'
	// ->
	'1,2,34,5,6'
```

### Trailing commas in array

空要素が4個ある配列を作成した。

```javascript
	let a = [,,,]
	a.length     // -> 3
	a.toString() // -> ',,'
```

末尾のカンマは要素やプロパティを付け加えたいときに役に立つ。
前の行に末尾カンマが付いていた場合、その行を変更することなく追加のプロパティを書くだけで済むからだ。
これによって差分管理もわかりやすくなる。
[Trailing commas](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Trailing_commas)

### Array equality is a monster

配列の==は危険がいっぱい。

```javascript
	[] == ''   // -> true
	[] == 0    // -> true
	[''] == '' // -> true
	[0] == 0   // -> true
	[0] == ''  // -> false
	[''] == 0  // -> true

	[null] == ''      // true
	[null] == 0       // true
	[undefined] == '' // true
	[undefined] == 0  // true

	[[]] == 0  // true
	[[]] == '' // true

	[[[[[[]]]]]] == '' // true
	[[[[[[]]]]]] == 0  // true

	[[[[[[ null ]]]]]] == 0  // true
	[[[[[[ null ]]]]]] == '' // true

	[[[[[[ undefined ]]]]]] == 0  // true
	[[[[[[ undefined ]]]]]] == '' // true
```

空の配列には気をつける必要がある。
[7.2.13 Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison)

### undefined and Number

Numberのコンストラクタに引数を渡さないと、返り値は0になる。
引数のある関数に引数を渡さなかった場合、仮引数はundefinedになる。
従ってNumberにundefinedを渡すと返り値もundefinedになるだろうと思うが、実際はNaNになる。

```javascript
	Number()          // -> 0
	Number(undefined) // -> NaN
```

仕様によると、
・引数がなかった場合は0とする
・それ以外の場合はToNumber()を呼ぶ
・ToNumber(undefined)はNaNになる

[20.1.1 The Number Constructor](https://www.ecma-international.org/ecma-262/#sec-number-constructor)
[7.1.3 ToNumber(argument)](https://www.ecma-international.org/ecma-262/#sec-tonumber)

### parseInt is a bad guy

parseIntはバッドガイだ。

```javascript
	parseInt('f*ck');     // -> NaN
	parseInt('f*ck', 16); // -> 15
```

parseIntは理解できない文字に出会うまでパースを続けるが、出会ったらエラーを出さずにそこまでの値を返してしまう。
'f*ck'の'f'は16進数で15である。
parseIntは無限大ですら整数解析してしまう。

```javascript
	parseInt('Infinity', 10) // -> NaN
	parseInt('Infinity', 18) // -> NaN...
	parseInt('Infinity', 19) // -> 18
	parseInt('Infinity', 23) // -> 18...
	parseInt('Infinity', 24) // -> 151176378
	parseInt('Infinity', 29) // -> 385849803
	parseInt('Infinity', 30) // -> 13693557269
	parseInt('Infinity', 34) // -> 28872273981
	parseInt('Infinity', 35) // -> 1201203301724
	parseInt('Infinity', 36) // -> 1461559270678...
	parseInt('Infinity', 37) // -> NaN
```

nullにも注意しなければならない。

```javascript
	parseInt(null, 24) // -> 23
```

nullは何故か文字列'null'に変換されてしまい、その後通常のパースが行われる。
基数23までは'n'が解析できないのでNaNが返ってくる。
基数24で'n'が理解できるようになり結果が23になる。
基数31で'u'までパースされ、結果は1112745になる。
基数を37以上にすると再びNaNになる。

[parseInt(null, 24) === 23… wait, what?](https://stackoverflow.com/questions/6459758/parseintnull-24-23-wait-what)

8進数の罠も忘れてはいけない。

```javascript
	parseInt('06'); // 6
	parseInt('08'); // 8 ES5
	parseInt('08'); // 0 ES5未対応
```

引数が'0'で始まる場合、基数が8になるか10になるかは実装依存である。
ES5では10進数であることを要求しているが、全てのブラウザがそのように実装されているとは限らない。
そのため、parseIntには必ず基数を指定しなければならない。

```javascript
	parseInt({ toString: () => 2, valueOf: () => 1 }) // -> 2
	Number({ toString: () => 2, valueOf: () => 1 })   // -> 1
```

### Math with true and false

```javascript
	true + true // -> 2
	(true + true) * (true + true) - true // -> 3
```

Numberに値を与えると数値に変換されるが、trueを与えると1になるのは自明であろう。

```javascript
	Number(true) // -> 1
```

単項演算子`+`は続く値を数値に変換しようとする。
これは整数と浮動小数の文字列表現、そしてtrue、false、nullに対応している。
それ以外の値に対してはNaNになる。
つまり、`+true`は1になる。

```javascript
	+true // -> 1
```

加算・乗算の際にはJavaScriptの内部関数ToNumber()が呼び出されるが、これは以下のような仕様になっている。
[If argument is true, return 1. If argument is false, return +0.](https://www.ecma-international.org/ecma-262/#sec-tonumber)
そのため、真偽値を通常の数値と同じように計算することが可能になってしまうというわけだ。

[12.5.6 Unary + Operator](https://www.ecma-international.org/ecma-262/#sec-unary-plus-operator)
[12.8.3 The Addition Operator (+)](https://www.ecma-international.org/ecma-262/#sec-addition-operator-plus)

### HTML comments are valid in JavaScript

昔懐かし、HTMLコメント`<!--`はJavaScriptでも有効なコメントだ。

```javascript
	// valid comment
	<!-- valid comment too
```

HTML形式コメントは、`<script>`タグを理解しないブラウザで動かなくならないために作られたのものだ。
しかし、その対象のブラウザ`Netscape 1.x`はもはや存在しないから、HTML形式コメントを入れる意味は全く無い。

Node.jsはV8エンジンに基づいているから、HTML形式コメントについても未だに対応している。
むしろ完全に仕様の一部となっている。

[B.1.3 HTML-like Comments](https://www.ecma-international.org/ecma-262/#sec-html-like-comments)

### NaN is a number

NaNは数値型である。

```javascript
	typeof NaN // -> 'number'
```

typeofとinstanceofの仕様は以下のとおりだ。

[12.5.5 The typeof Operator](https://www.ecma-international.org/ecma-262/#sec-typeof-operator)
[12.10.4 Runtime Semantics: InstanceofOperator(O,C)](https://www.ecma-international.org/ecma-262/#sec-instanceofoperator)

### [] and null are objects

`[]`とnullはオブジェクトである。

```javascript
	typeof []   // -> 'object'
	typeof null // -> 'object'
	
	// しかしinstanceではない
	null instanceof Object // false
```

typeof演算子は、[対応テーブル](https://www.ecma-international.org/ecma-262/#table-35)に従って文字列を返す。
従ってcallを実装していないオブジェクト、およびnullは"object"になる。

toStringメソッドを使うと、objectの詳しい内容まで確認できる。

```javascript
	Object.prototype.toString.call([])
	// -> '[object Array]'

	Object.prototype.toString.call(new Date)
	// -> '[object Date]'

	Object.prototype.toString.call(null)
	// -> '[object Null]'
```

### Magically increasing numbers

```javascript
	999999999999999  // -> 999999999999999
	9999999999999999 // -> 10000000000000000

	10000000000000000       // -> 10000000000000000
	10000000000000000 + 1   // -> 10000000000000000
	10000000000000000 + 1.1 // -> 10000000000000002
```

これは浮動小数点演算の標準規格IEEE 754-2008に従った動作であり、このスケールでは最も近い偶数に丸められてしまう。
[6.1.6 The Number Type](https://www.ecma-international.org/ecma-262/#sec-ecmascript-language-types-number-type)
[IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) on Wikipedia

### Precision of 0.1 + 0.2

浮動小数演算では致命的な間違いが発生する。

```javascript
	0.1 + 0.2 // -> 0.30000000000000004
	(0.1 + 0.2) === 0.3 // -> false
```

StackOverflowの質問[Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken)に理由が書いてある。
0.2や0.3という値は、実際は真の値の近似表示である。
近似値0.2の真の値は見た目の値よりも大きく、近似値0.3の真の値は見た目の値よりも小さい。
近似値0.1と0.2の和は近似値0.3の真の値よりも大きくなり、そのため近似値0.3の真の値とも一致しない。

この問題は[0.30000000000000004.com](http://0.30000000000000004.com/)というWebサイトが作られるほどよく知られている話である。
JavaScriptのみならず、浮動小数点演算の存在する全ての言語で発生する現象だ。

### Patching numbers

NumberやStringなどのラッパーオブジェクトに勝手にメソッドを追加できる。

```javascript
	Number.prototype.isOne = function () {
	  return Number(this) === 1
	}

	1.0.isOne() // -> true
	1..isOne()  // -> true
	2.0.isOne() // -> false
	(7).isOne() // -> false
```

他のオブジェクトと同じように拡張することができるが、到底勧められない。

[20.1 Number Objects](https://www.ecma-international.org/ecma-262/#sec-number-objects)

### Comparison of three numbers

```javascript
	1 < 2 < 3 // -> true
	3 > 2 > 1 // -> false
```

そもそも3数の評価は想定しているだろう動作をしていない。

```javascript
	1 < 2 < 3 // 先に1<2が評価
	true  < 3 // trueは数値型にすると1
	1     < 3 // -> true

	3 > 2 > 1 // 先に3>2が評価
	true  > 1 // trueは数値型にすると1
	1     > 1 // -> false
```

`>`を`>=`にすることで、この場合は動くようになる。

```javascript
	3 > 2 >= 1 // true
```

関係演算子の詳細については以下を参照。
[12.10 Relational Operators](https://www.ecma-international.org/ecma-262/#sec-relational-operators)

### Funny math

JavaScriptでの演算は、想定してなかった結果になることがしばしばある。

```javascript
	 3  - 1  // -> 2
	 3  + 1  // -> 4
	'3' - 1  // -> 2
	'3' + 1  // -> '31'

	'' + '' // -> ''
	[] + [] // -> ''
	{} + [] // -> 0
	[] + {} // -> '[object Object]'
	{} + {} // -> '[object Object][object Object]'

	'222' - -'111' // -> 333

	[4] * [4]       // -> 16
	[] * []         // -> 0
	[4, 4] * [4, 4] // NaN
```

最初の4例はどうなっているのか。
加算演算子でどうなるかの一覧は次のとおりだ。

```javascript
	Number  + Number  -> 加算
	Boolean + Number  -> 加算
	Boolean + Boolean -> 加算
	Number  + String  -> 文字列連結
	String  + Boolean -> 文字列連結
	String  + String  -> 文字列連結
```

それ以外の例についてはどうか。
`[]`と`{}`には、加算の前に暗黙的にToPrimitiveとToStringメソッドが呼び出されているのだ。
仕様の詳細については以下を参照。

[12.8.3 The Addition Operator (+)](https://www.ecma-international.org/ecma-262/#sec-addition-operator-plus)
[7.1.1 ToPrimitive(input [,PreferredType])](https://www.ecma-international.org/ecma-262/#sec-toprimitive)
[7.1.12 ToString(argument)](https://www.ecma-international.org/ecma-262/#sec-tostring)

### Addition of RegExps

正規表現リテラルにアクセスできることを知っているか？

```javascript
	// toStringを上書き
	RegExp.prototype.toString = function() {
	  return this.source
	}

	/7/ - /5/ // -> 2
```

[21.2.5.10 get RegExp.prototype.source](https://www.ecma-international.org/ecma-262/#sec-get-regexp.prototype.source)

### Strings aren't instances of String

文字列は文字列型ではない。

```javascript
	'str' // -> 'str'
	typeof 'str' // -> 'string'
	'str' instanceof String // -> false
```

Stringコンストラクタはstringを返す。

```javascript
	typeof String('str')   // -> 'string'
	String('str')          // -> 'str'
	String('str') == 'str' // -> true
```

newを付けると結果が変わる。

```javascript
	new String('str') == 'str' // -> true
	typeof new String('str')   // -> 'object'
```

newのついたStringはObjectだ。

```javascript
	new String('str') // -> [String: 'str']
```

Stringコンストラクタの仕様は以下に記載されている。
[21.1.1 The String Constructor](https://www.ecma-international.org/ecma-262/#sec-string-constructor)

### Calling functions with backticks

引数をそのまま返す関数を実装する。

```javascript
	function f(...args) {
	  return args
	}
```

以下の結果になることは想像に難くない。

```javascript
	f(1, 2, 3) // -> [ 1, 2, 3 ]
```

だが、関数をバッククォートで呼び出せることは知っているか？

```javascript
	f`true is ${true}, false is ${false}, array is ${[1,2,3]}`
	// -> [ [ 'true is ', ', false is ', ', array is ', '' ],
	// ->   true,
	// ->   false,
	// ->   [ 1, 2, 3 ] ]
```

これはタグ付きテンプレートリテラルと呼ばれる機能で、バッククォート内に書かれたテキストがタグ関数fに渡されることになる。
第一引数には文字列を`${}`で分割した配列が入ってきて、第二引数以降は`${}`の式の値が順に入ってくる。

```javascript
	function template(strings, ...keys) {
	  // do something with strings and keys…
	}
```

JavaScriptの中にCSSを書く[styled-components](https://www.styled-components.com/)ライブラリは、Reactコミュニティで人気である。

[12.3.7 Tagged Templates](https://www.ecma-international.org/ecma-262/#sec-tagged-templates)

### Call call call

```javascript
	console.log.call.call.call.call.call.apply(a => a, [1, 2])
```

警告。
訓練を受けていない方が真似すると動悸・息切れ・眩暈等の症状が現れたり、最悪の場合死に至ることもあります。

[19.2.3.3 Function.prototype.call(thisArg, ...args)](https://www.ecma-international.org/ecma-262/#sec-function.prototype.call)
[**19.2.3.1 ** Function.prototype.apply(thisArg, argArray)](https://www.ecma-international.org/ecma-262/#sec-function.prototype.apply)

### A constructor property

```javascript
	const c = 'constructor'
	c[c][c]('console.log("WTF?")')() // > WTF?
```

順に見ていこう。

```javascript
	// 'constructor'という文字列を定義する
	const c = 'constructor'

	// cはstring型
	c // -> 'constructor'

	// stringのコンストラクタ
	c[c] // -> [Function: String]

	// コンストラクタのコンストラクタ
	c[c][c] // -> [Function: Function]

	// Functionコンストラクタに引数を渡す
	c[c][c]('console.log("WTF?")') // -> [Function: anonymous]

	// 即時関数で呼ぶ
	c[c][c]('console.log("WTF?")')() // > WTF?
```

`Object.prototype.constructor`は作成したインスタンスへの参照を返す。
文字列であればString、数値であればNumberといった具合だ。

[Object.prototype.constructor](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor) at MDN
[19.1.3.1 Object.prototype.constructor](https://www.ecma-international.org/ecma-262/#sec-object.prototype.constructor)

### Object as a key of object's property

```javascript
	{ [{}]: {} } // -> { '[object Object]': {} }
```

これは計算されたプロパティ名という記法だ。
`[]`にObjectを渡すと文字列に変換され、'[object Object]'というキー名になる。

```javascript
	({[{}]:{[{}]:{}}})[{}][{}] // -> {}

	// structure:
	// {
	//   '[object Object]': {
	//     '[object Object]': {}
	//   }
	// }
```

オブジェクトリテラルについては以下を参照。
[Object initializer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer) at MDN
[12.2.6 Object Initializer](http://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer)

### Accessing prototypes with \_\_proto__

知ってのとおり、プリミティブ型にプロトタイプはない。
だが\_\_proto__でプロトタイプを取得できる。

```javascript
	(1).__proto__.__proto__.__proto__ // -> null
```

プリミティブ型のプロトタイプを呼ぼうとすると、ToObjectメソッドが自動的に呼ばれてラッパーオブジェクトになる。

```javascript
	(1).__proto__ // -> [Number: 0]
	(1).__proto__.__proto__ // -> {}
	(1).__proto__.__proto__.__proto__ // -> null
```

\_\_proto__の詳細については以下を参照。
[B.2.2.1 Object.prototype.proto](https://www.ecma-international.org/ecma-262/#sec-object.prototype.__proto__)
[7.1.13 ToObject(argument)](https://www.ecma-international.org/ecma-262/#sec-toobject)

### `${{Object}}`

以下の答えは？

```javascript
	`${{Object}}`
```

こうなる。

```javascript
	// -> '[object Object]'
```

まずはObjectをショートハンド`{Object}`で定義する。
次にテンプレートリテラルに突っ込むことでtoStringメソッドが呼ばれ、文字列'[object Object]'になる。


[12.2.9 Template Literals](https://www.ecma-international.org/ecma-262/#sec-template-literals)
[Object initializer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer) at MDN

### Destructuring with default values

yはいくつになるか。

```javascript
	let x, { x: y = 1 } = { x }; y;
```

答えは1。

```javascript
	let x, { x: y = 1 } = { x }; y;
	//  ↑       ↑           ↑    ↑
	//  1       3           2    4
```

1：xを定義。値は未定義。
2：xをオブジェクトのプロパティにする。
3：分割代入でプロパティxの値を取り出してyに代入する。未定義なのでデフォルト値1が使われる。
4：yの値を返す。

[Object initializer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer) at MDN

### Dots and spreading

```javascript
	[...[...'...']].length // -> 3
```

何故3か。
[スプレッド演算子](http://www.ecma-international.org/ecma-262/6.0/#sec-array-initializer)を使うと`@@iterator`メソッドが呼び出され、ループに使うイテレータが返される。
文字列のイテレータは、文字列を1文字ずつの配列にする。
文字列'...'は3文字であり、従って答えは3になる。

```javascript
	[...'...']             // -> [ '.', '.', '.' ]
	[...[...'...']]        // -> [ '.', '.', '.' ]
	[...[...'...']].length // -> 3
```

もっと長くしても結果は同じになる。

```javascript
	[...'...']                 // -> [ '.', '.', '.' ]
	[...[...'...']]            // -> [ '.', '.', '.' ]
	[...[...[...'...']]]       // -> [ '.', '.', '.' ]
	[...[...[...[...'...']]]]  // -> [ '.', '.', '.' ]
```

### Labels

JavaScriptのラベルはあまり知られていないが、多言語とは異なる特徴を持っている。

```javascript
	foo: {
	  console.log('first');
	  break foo;
	  console.log('second');
	}

	// > first
	// -> undefined
```

ラベル付きステートメントはbreakおよびcontinueと共に使う。
ラベルを用いて範囲を指定し、breakで実行を中断するか、continueで次のループに進むかを選択できる。
上記例では`console.log('first');`の後でbreakして実行を中断している。

[13.13 Labelled Statements](https://tc39.github.io/ecma262/#sec-labelled-statements)
[Labeled statements](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label) at MDN

### Nested labels

```javascript
	a: b: c: d: e: f: g: 1, 2, 3, 4, 5; // -> 5
```

ラベルはネストできる。
[12.16 Comma Operator (,)](https://www.ecma-international.org/ecma-262/#sec-comma-operator)

### Insidious try..catch

```javascript
	(() => {
	  try {
	    return 2;
	  } finally {
	    return 3;
	  }
	})()
```

答えは3。
[13.15 The try Statement](https://www.ecma-international.org/ecma-262/#sec-try-statement)

### Is this multiple inheritance?

これは多重継承ではないか？

```javascript
	new (class F extends (String, Array) { }) // -> F []
```

いいえ。

注目する点は`(String, Array)`だ。
グループ化演算子は最後の値を返すので、`(String, Array)`の値は`Array`になる。
従って、このクラスは単に`Array`を継承しているだけだ。

[14.5 Class Definitions](https://www.ecma-international.org/ecma-262/#sec-class-definitions)
[12.16 Comma Operator (,)](https://www.ecma-international.org/ecma-262/#sec-comma-operator)

### A generator which yields itself

自分自身を返すジェネレータを考えてみる。

```javascript
	(function* f() { yield f })().next()
	// -> { value: [GeneratorFunction: f], done: false }
```

見てのとおり、返ってくるのは値fを持つオブジェクトだ。
つまり、こうなる。

```javascript
	(function* f() { yield f })().next().value().next()
	// -> { value: [GeneratorFunction: f], done: false }

	// and again
	(function* f() { yield f })().next().value().next().value().next()
	// -> { value: [GeneratorFunction: f], done: false }

	// and again
	(function* f() { yield f })().next().value().next().value().next().value().next()
	// -> { value: [GeneratorFunction: f], done: false }
```

このようになる理由は以下を参照。
[25 Control Abstraction Objects](https://www.ecma-international.org/ecma-262/#sec-control-abstraction-objects)
[25.3 Generator Objects](https://www.ecma-international.org/ecma-262/#sec-generator-objects)

### A class of class

```javascript
	(typeof (new (class { class () {} }))) // -> 'object'
```

クラス内でクラスを宣言しており、エラーになるはずなのに文字列'object'が返ってくる。

ES5以降、キーワードもプロパティ名として使用することができる。
従って以下の文は有効だ。

```javascript
	const foo = {
	  class: function() {}
	};
```

さて、ES6においてメソッドの短縮構文が導入された。
つまり上記はこう書ける。

```javascript
	class {
	  class() {}
	}
```

これはただのクラスであり、従ってその型は'object'になる。

[14.3 Method Definitions](https://www.ecma-international.org/ecma-262/#sec-method-definitions)
[14.5 Class Definitions](https://www.ecma-international.org/ecma-262/#sec-class-definitions)

### Non-coercible objects

[well-known symbols](https://www.ecma-international.org/ecma-262/#sec-well-known-symbols)の型強制を回避する。

```javascript
	function nonCoercible(val) {
	  if (val == null) {
	    throw TypeError('nonCoercible should not be called with null or undefined')
	  }

	  const res = Object(val)

	  res[Symbol.toPrimitive] = () => {
	    throw TypeError('Trying to coerce non-coercible object')
	  }

	  return res
	}
```

こうやって使える。

```javascript
	// objects
	const foo = nonCoercible({foo: 'foo'})

	foo * 10      // -> TypeError: Trying to coerce non-coercible object
	foo + 'evil'  // -> TypeError: Trying to coerce non-coercible object

	// strings
	const bar = nonCoercible('bar')

	bar + '1'                 // -> TypeError: Trying to coerce non-coercible object
	bar.toString() + 1        // -> bar1
	bar === 'bar'             // -> false
	bar.toString() === 'bar'  // -> true
	bar == 'bar'              // -> TypeError: Trying to coerce non-coercible object

	// numbers
	const baz = nonCoercible(1)

	baz == 1             // -> TypeError: Trying to coerce non-coercible object
	baz === 1            // -> false
	baz.valueOf() === 1  // -> true
```

[A gist by Sergey Rubanov](https://gist.github.com/chicoxyzzy/5dd24608e886adf5444499896dff1197)
[6.1.5.1 Well-Known Symbols](https://www.ecma-international.org/ecma-262/#sec-well-known-symbols)

### Tricky arrow functions

アロー関数がある。

```javascript
	let f = () => 10
	f() // -> 10
```

だが下の例は思った通りに動かない。

```javascript
	let f = () => {}
	f() // -> undefined
```

`{}`を期待したのに`undefined`が返ってきた。
中括弧はアロー関数の構文の一部と見做されるため、関数の本体がなくなる。

### arguments and arrow functions

引数のある関数だ。

```javascript
	let f = function(){
	  return arguments;
	}
	f('a'); // -> { '0': 'a' }
```

アロー関数にしよう。

```javascript
	let f = () =>  arguments;
	f('a'); // -> Uncaught ReferenceError: arguments is not defined
```

アロー関数は文字数が短く、`this`をレキシカルに固定できる、これまでの`function`の短縮構文だ。
ところでアロー関数は引数を`arguments`にバインドしない。
かわりにスプレッド演算子で引数を受け取る必要がある。

```javascript
	let f = (...args) => args;
	f('a');
```

[Arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) at MDN.

### Tricky return

区別が付くだろうか。

```javascript
	(function () {
	  return
	  {
	    b : 10
	  }
	})() // -> undefined
	
	(function () {
	  return {
	    b : 10
	  }
	})() // -> { b: 10 }
```

これは自動セミコロン挿入機能によるものである。
改行の後には、大抵セミコロンが自動的に挿入されてしまう。
前者の例ではreturnと`{`の間にセミコロンが入り、関数はundefinedを返し、オブジェクトリテラルが評価されることはない。

[11.9.1 Rules of Automatic Semicolon Insertion](https://www.ecma-international.org/ecma-262/#sec-rules-of-automatic-semicolon-insertion)
[13.10 The return Statement](https://www.ecma-international.org/ecma-262/#sec-return-statement)

### Accessing object properties with arrays

```javascript
	var obj = { property: 1 }
	var array = ['property']

	obj[array] // -> 1
```

多次元配列にしたらどうなる？

```javascript
	var map = {}
	var x = 1
	var y = 2
	var z = 3

	map[[x, y, z]] = true
	map[[x + 10, y, z]] = true

	map["1,2,3"]  // -> true
	map["11,2,3"] // -> true
```

ブラケット記法`[]`は、渡された値をtoStringに通す。
配列に要素がひとつしかない場合、その結果は要素だけをtoStringしたのと同じ結果になる。

```javascript
	['property'].toString() // -> 'property'
```

### Null and Relational Operators

```javascript
	null > 0;  // false
	null == 0; // false

	null >= 0; // true
```

簡単にまとめると、『もし`null<0`が`false`であれば、`null>=0`は`true`である』
詳しい説明は[ここ](https://blog.campvanilla.com/javascript-the-curious-case-of-null-0-7b131644e274)にある。

### Number.toFixed() display different numbers

Number.toFixedはブラウザによって異なる結果になる。

```javascript
0.7875.toFixed(3) 
    // FireFox: -> 0.787
    // Chrome: -> 0.787
    // IE11: -> 0.788
0.7876.toFixed(3)
    // FireFox: -> 0.788
    // Chrome: -> 0.788
    // IE11: -> 0.788
```

[20.1.3.3 Number.prototype.toFixed (fractionDigits)](https://www.ecma-international.org/ecma-262//#sec-number.prototype.tofixed)

## Other resources

### [wtfjs.com](http://wtfjs.com/)

その不規則で矛盾に満ちていて直感的でないWeb言語について。

### [Wat](https://www.destroyallsoftware.com/talks/wat)

Gary Bernhardtが2012年のCodeMashで発表したライトニングトーク。

### [What the... JavaScript?](https://www.youtube.com/watch?v=2pL28CcEijU)

Kyle SimpsonsによるJavaScriptの素敵な仕様についてのトーク。
彼は、クリーンでエレガントで可読性の高いコードを作成し、オープンソースコミュニティに貢献できるよう人々を導きたいと考えている。

## License

[WTFPL 2.0](http://www.wtfpl.net/)ライセンスだ。


# まとめ

知らない仕様や、意味のわからない動作がたくさんあった。