JavaScript の Number
オブジェクトは、実数をあらわす。整数を表すクラスと別れていない。
新しい JavaScript (ECMAScript 2020) では BigInt
がプリミティブとして導入されたが, Number
を置き換えるものではない。
数値 (リテラル) は 123
, 123.4
または 1.23e-3
[浮動小数点表示] と記述する。
コンストラクタ Number(value)
に文字列を与えてもよい. parseFloat(str)
, parseInt(str, [radix])
でも数値オブジェクトを生成できる。
new Number(...)
してはならない。エラーにもならないが正常に動かない。
特別な値 NaN, ±Infinity も数値。JavaScript は変数に型がないので,「数値型だが数値ではない」を表すのに、ナル値と異なる値を使わざるをえない。
Number()
や String()
の相互変換数値や文字列に変換するとどうなるか。
値 | Number(値)
| String(値)
| parseInt(値)
| |
---|---|---|---|---|
undefined | NaN | "undefined" | NaN
| |
null | 0 | "null" | NaN | Number(null) は NaN になりそうだが、そうではない。
|
false | 0 | "false" | NaN
| |
true | 1 | "true" | NaN
| |
"true" | NaN | "true" | NaN
| |
NaN | NaN | "NaN" | NaN
| |
Infinity | Infinity | "Infinity" | NaN
| |
-Infinity | -Infinity | "-Infinity" | NaN
| |
"" | 0 | "" | NaN
| |
"3x" | NaN | "3x" | 3 | parseInt() は parse できるところまでで打ち切る
|
-1.5 | -1.5 | "-1.5" | -1 | parseInt() は 0に向かって丸める.
|
0 | 0 | "0" | 0
| |
1.5 | 1.5 | "1.5" | 1
| |
[] | 0 | "" | NaN
| |
{} | NaN | "[object Object]" | NaN
|
parseInt()
は, 数値と「数値で始まる文字列」でないものはすべてNaN
に変換。その割に文字列の途中までは parse する。
Number()
は数値に型変換しようとする。Number("Infinity")
は Infinity
になる。それ以外、数値でない文字列は全部 NaN
になる。
Number(Symbol('foo'))
は TypeError
例外を発生。シンボルからの型変換はできない。
Number({})
が NaN
になる一方で, []
が 0になる。""
と同じノリか。
実際のコーディングでは, Number()
で変換したうえで、NaN
かどうかで弾くのが現実的、か。
parseInt(str, [radix])
と Number#toString([radix])
を使えばよい。
parseInt('ffff', 16) #=> 65535
Number('65500.456').toString(16) #=> "ffdc.74bc6a7ef8"
リテラルでは, 0b を頭に付ければ2進数, 0o なら8進数, 0x なら16進数になる。
JavaScript 仕様により, IEEE 754 倍精度64bitフォーマットと決まっている。10進での有効桁数は15桁。次の定数が決まっている。
Number.EPSILON
Number.MAX_SAFE_INTEGER
Number.MAX_VALUE
ビット演算子の挙動に注意を要する。JavaScript の数値は実数だが、ビット演算子は整数しか受け付けない。暗黙に丸められる。何だって!
~
bitwiseNOT
(~parseInt('fffffff', 16)).toString(16) #=> "-10000000"
%
剰余
456.12 % 123.45 #=> 85.77
<<
, >>
, >>>
123.45 << 3.2 #=> 984. 123 << 3 と同じ
&
, ^
, |
x = 15.2 x / 5 | 0 #=> 3. ビット論理和のほうが除算より優先順位が低いのも活用.
0除算はエラーにならない。NaNが顔を出す
-3/0 #=> -Infinity +3/0 #=> Infinity 0/0 #=> NaN
NaN
の神秘NaN
は ==
であれ ===
であれ、自分自身との比較も false になる。null
のほうは、自分自身との比較は true になるのに。
そのため isNaN()
関数がある。
実際には、例えば1以上の整数が欲しいなら > 0
するだけで NaN
も弾ける。
グローバルの isNaN()
関数と Number.isNaN()
があり、挙動が異なる。グローバルのほうは互換性のためにある。常に Number.isNaN()
を使うこと。
isNaN()
Number
オブジェクトに型変換する。その結果が NaN
であれば true
を返す。ということは, undefined, 数値に変換できない文字列は true. {}
も true. 問題は, null
を与えると false
になってしまう。Number(null)
が 0 になる問題がここで現れる。
isNaN(true) #=> false isNaN(false) #=> false.
Number.isNaN(obj)
Number
ではない場合, false.
Number
だった場合, obj が NaN
の場合, true.
そうすると, undefined, 任意の文字列 (数値に変換できるものであっても) は false になる。
Number()
で数値に整えた上で、もし必要であれば Number.isNaN()
を呼び出せばいい。