JavaScript の算術演算子と数値変換
いちにぃさんのついーとを見て String の valueOf 絡みのことを調べているが、これは思った以上にややこしい。そして思わぬ収穫が。 /[Mm]ath/
2010-12-20 22:55:17結論から言うと、算術演算子は、内部で被演算項に対して数値変換を施してから演算を行うようになっている。従って、次のようなコードは結果が数値型になる(ことが期待される): "1" - "2"; // => -1 #JavaScript /[Mm]ath/
2010-12-20 23:17:34確認は Firefox, Chrome でとった。そしてこれは ECMAScript 仕様に則った挙動である。 #JavaScript /[Mm]ath/
2010-12-20 23:59:25ここで、数値型への変換が呼ばれる前に、 valueOf が呼ばれる場合がある。(なお ECMAScript の仕様ではそれぞれ "ToNumber", "GetValue" となっている) #JavaScript /[Mm]ath/
2010-12-21 00:24:42呼ばれる場合がある、というのは必ずしも valueOf は呼ばれないということである。実は valueOf と GetValue は等価ではない。 #JavaScript /[Mm]ath/
2010-12-21 00:28:15仕様にある "GetValue" というのは、あくまで「ECMAScript のオブジェクトから primitive 値を取得する」という意味である。 #JavaScript /[Mm]ath/
2010-12-21 00:30:41そして Object は全てのオブジェクトの継承元であるから、 ***.prototype.valueOf は、Number や String にも(nativeに)実装されている。 #JavaScript /[Mm]ath/
2010-12-21 00:33:14従って JavaScript のオブジェクトなら全て GetValue の時に valueOf が呼ばれていることになる(そしてこの呼び出しは時に script レベルで再帰的でもあるかもしれない)。 #JavaScript /[Mm]ath/
2010-12-21 00:35:24ここで重要なのが primitive 値だ。 primitive な string や number は普通のオブジェクトとは全く異なる。これは”GetValue が返すべき値そのもの”である(たぶん。 #JavaScript /[Mm]ath/
2010-12-21 00:37:20数値リテラル初期化子や、文字列リテラル初期化子が生成する値は、いずれも primitive 値である。それぞれ、Number, String の instance で は な い。 #JavaScript /[Mm]ath/
2010-12-21 00:38:21例えば +3 というコード片において、3 は primitive 値 [3] を生成するから、 [GetValue] によってその値自身 [3] を返す。ここで valueOf が呼び出される余地はない(ハズである。 #JavaScript /[Mm]ath/
2010-12-21 00:42:57((ここら辺まで ECMAScript とか valueOf とかの実装寄りの話 / こっからついでに分かった話)) /[Mm]ath/
2010-12-21 00:56:43JavaScript で文字列->数値に変換するときは、よく parseInt 関数が使われる。(parseInt を用いるのが最も一般的だと思われる) #JavaScript /[Mm]ath/
2010-12-21 00:59:22ところが、parseInt には色々と問題がある。ブラウザによって必ずしも同じ値を返さなかったりするのはまぁいつものことだが、引数の与え方によっては 8 進数表記だと解釈されたりしてしまう。 #JavaScript /[Mm]ath/
2010-12-21 01:02:21例えば、 parseInt("010") は基数を指定していないため、多くのブラウザで 8 が返ってくる。ちなみに IE9 では 10 が返ってきた。 #JavaScript /[Mm]ath/
2010-12-21 01:07:05ECMAScript draft 5th ed. では、第二引数省略時は必ず 10 進表記で変換することになったらしいので、IE9 の挙動が正しい。 #JavaScript /[Mm]ath/
2010-12-21 01:08:28と言ってもそんなのは最近の出来事である。昔の draft では実装依存だったらしいので、parseInt の第二引数を指定しない場合の結果はあまり期待できない。(なので、第二引数には必ず 10 をつけろ、と言われている) #JavaScript /[Mm]ath/
2010-12-21 01:09:50また、parseInt は科学表記(2×10^-5 を表す 2.0e-5 など)に対応していない。 parse 中に、期待されない文字が現れた場合以降の文字は切り捨てられる。 #JavaScript /[Mm]ath/
2010-12-21 01:12:18例えば: parseInt("2e-3"); // => 2 parseInt("1abcd"); // => 1 #JavaScript /[Mm]ath/
2010-12-21 01:13:15