以下の記事が話題になった
NaN === NaN
はfalse
であるconsole.log(NaN == false); // → false
- グローバルオブジェクトにある
isNaN
とNumber.isNaN
は挙動が違う - 配列の
indexOf
でNaN
は見つけられない
ということさえ覚えておけばよさそうで、あとはやろうと思えばNaN === NaN
をboolean以外にもできる(まぁやらないよね)っていう話だった
ところで
このブログの中の余談1にあったNaNのビット表現
を説明する箇所で、以下の検証コードを挙げられていたが、自分の知識不足で何をしているのかがわからなかった
なので、ここを理解するようにする
Float64ArrayとかUint8Arrayとか
Float64Array
はArrayBuffer
に格納されたバイト配列の各8バイトを浮動小数点としてみなすというもの
次にUint8Array
はArrayBuffer
に格納されたバイト配列の各1バイトを0 から 255までの値としてみなすというもの
例えば、new ArrayBuffer(16)
の場合、Float64Array
とUint8Array
の関係は以下のようになっている
コードを読み解く
最初にFloat64Array
のコンストラクタ引数に1
を指定しているので8バイトの浮動小数点がはいるよと宣言しており
そこにNaN
を代入し、Uint8Array
で宣言した各1バイトをみると
console.log(charView.join(',')); // → 0,0,0,0,0,0,248,127
のようになっている
リトルエンディアンなので、逆から並べてビット表現をみると次の図の(1)のようになる
このとき、charView[6] = 0xf0;
をした場合(図の(2))では指数部のビットがすべて 1 のままだが、仮数部が全て0なのでInfinity
になる
次に、charView[6] = 0xf4;
をした場合(図の(3))は指数部のビットがすべて 1 のままで、仮数部が全て0ではないのでNaN
になる
このように、NaN
は複数通りのビット表現を持つことが許されている
ちなみに、理由はそういう仕様だから
という説明をしていたことが理解できた
他参考記事
https://tc39.es/ecma262/#sec-islooselyequal
https://yosuke-furukawa.hatenablog.com/entry/2018/01/30/174425