JavaScript

JavaScript の Number() は副作用がある可能性がある

More than 1 year has passed since last update.

たまたまTwitterを見てたら以下のようなツイートを見かけました。

image

つまり、 isNumber っていう関数を作るなら一旦Numberでキャストした値と同一かどうかを比較すれば良いと。おそらく NaN を省いた number 型を true にしたいのかなという感じがする (NaN === NaN は必ず false)。

ただこれには問題があるらしく、 V8 のOptimizerリーダーである bmeurer から下記のようなレスが付いてました。

image

Number() では意図しない副作用があるかもしれない」という意味のレス。最初意味がわからなくて、「おや?」と思ったんですけど、その後で補足が。

image

ToPrimitive関数が呼ばれてしまい、意図しないJSの動きをするかも。」とのこと。

つまり、

var a = {
  x: 1,
  [Symbol.toPrimitive]: function() {
    this.x++;
    return this.x;
  }
};

みたいなオブジェクトがあったら、 Number 関数が呼ばれる度に a.x がインクリメントされてしまう。

$ node > Number(a)
<- 2
$ node > Number(a)
<- 3
$ node > Number(a)
<- 4

これだけじゃなくて、 +a でも呼ばれるはず

$ node > +a
<- 5
$ node > +a
<- 6
$ node > +a
<- 7

上記の条件(NumberだけどNaNをfalseにしつつ、副作用を伴わない)を満たすisNumber関数を作るなら、横着せずにちゃんと typeof a === 'number'Number.isNaN でチェックするのがいいんだろう。

いやでも待てよ、それだとすると、副作用を伴わずにNumber型にキャストするっていう手段はないのか・・・?どうしよう、って思ったら Dr. Axel 先生からの締め。

image

parseNumber っていう関数あるといいのかもねーっていう。こうしてJSにまた1つ関数が追加されるのかしら。