JavaScriptの気持ちになってみた
時々Swiftの話が出てくるのは気分の問題
JavaScript書いたことないので解釈間違えてそう
Thanks for inventing #javascript! ;-) pic.twitter.com/NISVQTALWB
— Claudio De Sio (@cdesio) June 30, 2018
typeof NaN
typeof NaN
→ 'number'
これは別に普通ではなかろうか。そうでもないのか??いやまあ名前に反してるかもしれないが。
個人的にはこっちのほうが微妙↓↓
typeof typeof NaN
→ 'string'
いいのか文字列で。いいのか。はい。
Swiftはmetatype typeで返す。
type(of: type(of: Float.nan))
→ Float.Type
9999999999999999
9999999999999999
→ 10000000000000000
JavaScriptのNumberは実は64bit float。
符号部 | 指数部 | 仮数部 |
---|---|---|
0 | 10000110100 | 0001110000110111100100110111111000001000000000000000 |
これを10進数に戻すと 10000000000000000
になってしまう。
0.5 + 0.1 == 0.6
/ 0.1 + 0.2 == 0.3
0.5 + 0.1 == 0.6
→ true
符号部 | 指数部 | 仮数部 | |
---|---|---|---|
0.5 | 0 | 01111111110 | 0000000000000000000000000000000000000000000000000000 |
0.1 | 0 | 01111111011 | 1001100110011001100110011001100110011001100110011010 |
0.5+0.1 | 0 | 01111111110 | 0011001100110011001100110011001100110011001100110011 |
0.6 | 0 | 01111111110 | 0011001100110011001100110011001100110011001100110011 |
0.1 + 0.2 == 0.3
→ false
符号部 | 指数部 | 仮数部 | |
---|---|---|---|
0.1 | 0 | 01111111011 | 1001100110011001100110011001100110011001100110011010 |
0.2 | 0 | 01111111100 | 1001100110011001100110011001100110011001100110011010 |
0.1+0.2 | 0 | 01111111101 | 0011001100110011001100110011001100110011001100110100 |
0.3 | 0 | 01111111101 | 0011001100110011001100110011001100110011001100110011 |
浮動小数点数の宿命。
Math.max()
/ Math.min()
Math.max()
→ -Infinity
Math.min()
→ Infinity
仕様です。
各静的メソッドの構文は次のようになっている。
Math.max([value1[,value2[, ...]]])
Math.min([value1[,value2[, ...]]])
Swiftの max(_:_:)
と min(_:_:)
は1つ以上の引数を要するのでそもそもこんなことはできない。
加算演算子
加算演算子の処理方法はちゃんと仕様で決まっている。
以下意訳
lref
を左辺の評価結果とする。lval
をlref
の参照外しの結果とする。rref
を右辺の評価結果とする。rval
をrref
の参照外しの結果とする。lprim
をlval
をプリミティブ化したものとする。rprim
をrval
をプリミティブ化したものとする。lprim
とrprim
のどちらかがStringならそれぞれをStringにして結合結果を返す。そうでなければNumberにして和を返す。
[] + []
/ [] + {}
/ {} + []
[] + []
→ ''
[] + {}
→ '[object Object]'
{} + []
→ 0
配列の足し算は未定義っぽい。むずかしい。
'[object Object]'
については ''
と [object Object]
を足してみたのだろうなあと推測できなくはないが、 0
は厳しい。 0 + NaN
で NaN
になるならまだわかる。
ちなみに、
{} + {}
→ '[object Object][object Object]'
let a = [] let o = {} a + o
→ '[object Object]'
[] + {} === {} + []
→ true
等々となるので、 {} + []
が '[object Object]'
を返してくれさえすれば未定義といえど辻褄が合っているように見える。気がする。
(!+[]+[]+![]).length
(!+[]+[]+![]).length
→ 9
.length
はここでは関係ない。
! + []
→ true
あの…なんで ! + []
が成立するんでしょうか…。 [] + !
は !
が引数(?)を要求するのでさすがにダメ。
! + []
はさておき、! + [] + []
は true + []
→ 'true' + ''
→ 'true'
と考えればそれっぽい。
【追記ここから】
そういえば単項演算子に +
とかいうのいましたね…
expr
を左辺を評価したものとする- Numberに変換したものを返す
なので、 ! + []
→ ! (+ [])
→ !0
→ true
。
ご指摘ありがとうございました。
【ここまで】
expr
を右辺を評価したものとする。oldValue
をexpr
をBooleanに変換したものとする。oldValue
がtrue
ならfalse
、false
ならtrue
。
という処理をするので、 ![]
は ![]
→ !true
→ false
となるっぽい。じゃあなんで ! + []
が true
なのかと聞かれるとやはりわからない。
【追記ここから】
[]
は true
であり 0
であり、 0
は false
。なるほど。
【ここまで】
9+"1"
9+"1"
→ "91"
"1" が文字列なので文字列結合が実行される。
91 - "1"
91 - "1"
→ 90
減算演算子の場合は lprim
と rprim
の型にかかわらずNumberに変換した上で四則演算が実行される。
"a"
などが含まれている場合、 NaN
に変換されるので減算結果も NaN
になる。
等価演算子
仕様上、
==
の判断は
- 両辺が同じ型なら
===
の結果次第。 - 両辺がどちらも
null
かundefined
だったらtrue
。 - NumberとStringの比較の場合はStringの方をNumberに変換したうえで
==
で比較。 - Booleanの場合はそれをNumberに変換した上で
==
で比較。 - 両辺のどちらか一方がObjectだった場合はそちらをプリミティブ化したうえで
==
で比較。 - 以上のどれにも当てはまらない場合は
false
。
===
の処理は
- 両辺の型が違うなら
false
。 - Numberのとき、どちらかが
NaN
ならfalse
。同じ値ならtrue
(-0
と+0
は同じ値とみなす)。どれでもないならfalse
。 - Number以外のときは型の種類ごとに両辺が同じかどうかを判断。
となっている。
true + true + true === 3
true + true + true === 3
→ true
true
はStringではないのでNumberに変換した上で加算する。 true
は 1
扱い。
両辺ともに同じ数となるので結果は true
。
true == 1
/ true === 1
true == 1
→ true
true == 1
→ 1 == 1
→ 1 === 1
と経て最後は true
。
true === 1
→ false
両辺の型が違うので false
。
[] == 0
[] == 0
→ true
空の配列 []
をプリミティブ化した時に 0
になるので 0 === 0
で true
。
ちなみに空文字列で "" == 0
した場合も true
。
けっきょくよくわからなかったこと
【追記】解決した! + []
がなぜOKなのか!
はAdditiveExpressionということでいいんですかね
[] == 0
がtrue
で[""] == 0
がtrue
で["a"] == 0
がfalse
なのはなぜか- 空文字列と同様に空配列はfalseな感じがあるらしいが、それがどこに書いてあるのか仕様が長すぎてわからない
- 【追記】
[]
がtrue
で0
で0
がfalse
でobject
がtrue
というのが原因だろうが、ここまで来るともはや何が何だかわからない。
- 【追記】
- 空文字列と同様に空配列はfalseな感じがあるらしいが、それがどこに書いてあるのか仕様が長すぎてわからない
- Swiftで
[] + [:]
とやると[(key: AnyHashable, value: Any)]型になるのだが、この+
はどこからきたのか
むずかしい!
参考文献
typeof
- typeof 演算子 - JavaScript | MDN
- Types — The Swift Programming Language (Swift 4.2)
- type(of:) - Swift Standard Library | Apple Developer Documentation
浮動小数点数ツール
max
/ min
- ECMAScript® 2018 Language Specification
- Math.max() - JavaScript | MDN
- Math.min() - JavaScript | MDN
- max(_:_:) - Swift Standard Library | Apple Developer Documentation
- min(_:_:) - Swift Standard Library | Apple Developer Documentation
加算演算子
- Arithmetic operators - JavaScript | MDN
- Logical Operators - JavaScript | MDN
- ECMAScript® 2018 Language Specification
- https://www.ecma-international.org/ecma-262/9.0/#sec-additive-operators
- https://www.ecma-international.org/ecma-262/9.0/#sec-subtraction-operator-minus
- https://www.ecma-international.org/ecma-262/9.0/#sec-toprimitive
- https://www.ecma-international.org/ecma-262/9.0/#sec-ordinarytoprimitive
- 【追記】https://www.ecma-international.org/ecma-262/9.0/#sec-unary-plus-operator
等価演算子
- ECMAScript® 2018 Language Specification