ECMAScript とは JavaScript の根幹となる仕様の名称です。 型変換は ECMAScript 仕様に準じており、ここでは ECMAScript 2017 に沿った説明をしています。
ECMAScript 2017 では Number 型を表すリテラル表現として、NumericLiteral
の文法を定義しており、NumericLiteral
は更に次の4種類に分かれます。
- [11.8.3 Numeric Literals
- ECMAScript® 2017 Language Specification](http://www.ecma-international.org/ecma-262/8.0/#sec-literals-numeric-literals)
- octal and binary literals - ECMAScript 6 compatibility table
'use strict';
/**
* DecimalLiteral
* 整数部分が「"0" のみ」もしくは「[1-9] で始まる10進数」となる10進数値
*/
console.log(0); // 0
console.log(10); // 10
console.log(1.234); // 1.234
/**
* BinaryIntegerLiteral
* "0b" もしくは "0B" で始まる2進数値 (ES6 規定) ※IE11は未対応
*/
console.log(0b10); // 2
console.log(0B10); // 2
/**
* OctalIntegerLiteral
* "0o" もしくは "0O" で始まる8進数値 (ES6 規定) ※IE11は未対応
*/
console.log(0o10); // 8
console.log(0O10); // 8
/**
* HexIntegerLiteral
* "0x" もしくは "0X" で始まる16進数値
*/
console.log(0x10); // 16
console.log(0X10); // 16
8進数リテラルにはレガシーな書き方が一つあります。 (この記法は ES3 で仕様から取り除かれましたが、後方互換性の為に記述だけは残り、ES5 になって Strict Mode で使えなくなりました。)
<script>
/**
* LegacyOctalIntegerLiteral
* "0" から始まる数値は8進数として扱う
*/
console.log(010); // 8
</script>
<script>
'use strict';
010; // SyntaxError: Octal literals are not allowed in strict mode.
</script>
ECMAScript では型変換の外側には出てこない内部命令をいくつか定義しています。
ToNumber
は次の変換テーブル規則によって、Number
型に変換します。
引数の型 | 結果 |
---|---|
Undefined | NaN を返す |
Null | +0 を返す |
Boolean | 引数が true なら 1 を返し、引数が false なら +0 を返す |
Number | 引数をそのままの状態で返す(型変換をしない) |
String | 前後の空白文字を削除し、空文字ならば +0 を返す。NumericLiteral とほぼ同じ文法を持つ StringNumericLiteral を構文解析し、Number 値を返す(※) |
Symbol | TypeError 例外を投げる |
Object | ToNumber(ToPrimitive(arg, "number")) を呼び出す |
※StringNumericLiteral
と NumericLiteral
はよく似ていますが、次の違いがあるようです。
NOTE2: Some differences should be noted between the syntax of a StringNumericLiteral and a NumericLiteral:
- A StringNumericLiteral may include leading and/or trailing white space and/or line terminators.
- A StringNumericLiteral that is decimal may have any number of leading 0 digits.
- A StringNumericLiteral that is decimal may include a + or - to indicate its sign.
- A StringNumericLiteral that is empty or contains only white space is converted to +0.
- Infinity and -Infinity are recognized as a StringNumericLiteral but not as a NumericLiteral.
(日本語訳) StringNumericLiteralの構文とNumericLiteralの構文にはいくつかの違いがあります。
StringNumericLiteral
には、先頭または末尾に空白文字もしくは行終端文字が含まれます(訳注: 先頭/末尾の空白文字及び行終端文字は取り除かれます)- 10進数の
StringNumericLiteral
は先頭に任意の数の0
を持つことができます(訳注:StrDecimalLiteral
のことです。通常の数値リテラルにおけるDecimalLiteral
では先頭に0
を持つ10進数値を記述した場合、Strict Mode ではSyntaxError
例外を返し、非Strict Mode では後方互換性の為の機能として8進数リテラルと解釈されます)。 - 10進数の
StringNumericLiteral
には、符号を示す+
または-
が含まれます。 Infinity
と-Infinity
はStringNumericLiteral
として認識されますが、NumericLiteral
として認識されることはありません(訳注:Infinity
はコード文中ではグローバル変数として定義されており、数値リテラル表現ではありません)。
ToNumber
を呼び出す事で Number
型に変換する、最も基本的な関数です。
「暗黙の型変換」で Number
型に変換される時には、ToNumber
が呼び出されます。
(整数値に変換する場合には ToInteger
を使用するなど、機能別に多少の違いはありますが、ToInteger
も初めの処理で ToNumber
を呼び出しています)
'use strict';
console.log(Number('\n 1 \n')); // 1 (先頭/末尾の空白文字及び行終端文字は無視されます)
console.log(Number('')); // 0 (空文字には 0 を返します)
console.log(Number(undefined)); // NaN
console.log(Number(null)); // 0
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number(new Number(1))); // 1
console.log(Number({})); // NaN
console.log(Number({valueOf: function (){ return 1; }})); // 1
console.log(Number({valueOf: function (){ return '1'; }})); // 1
console.log(Number(Symbol())); // TypeError: Cannot convert a Symbol value to a number
+
演算子の前方に式(Expression)が存在しない場合、後続する式(Expression)を ToNumber
によって、Number
型に変換します。
変換ルールは「Number」もしくは「ToNumber」の節を参照して下さい。
'use strict';
console.log(+''); // 0
parseInt()
は第一引数を ToString
によって String
型に変換し、第二引数に与えられた基数を元に「N進数」の文字列として構文解析後、整数値の Number
型に変換します。
- 第二引数に指定可能な基数の範囲は「2~36」です
- 先頭の先頭/末尾の空白文字及び行終端文字は読み飛ばされます(ex: " 10" は "10" と解釈される)
- 数値文字列に後続する「数値以外の文字列」は読み飛ばされます(ex: "10px" は "10" と解釈される)
- 第二引数が省略され、先頭が "0x" もしくは "0X" で始まっている場合、16進数値として解釈されます
'use strict';
/**
* 第二引数を指定した場合
*/
console.log(parseInt('10', 8)); // 8
console.log(parseInt('FF', 16)); // 255
console.log(parseInt('0x10', 10)); // 0
console.log(parseInt('Z0', 36)); // 1260
console.log(parseInt('10', 1)); // NaN
console.log(parseInt('10', 37)); // NaN
/**
* 第二引数を省略した場合
*/
console.log(parseInt('\n 1 \n')); // 1 (先頭/末尾の空白文字及び行終端文字は無視されます)
console.log(parseInt('0x10')); // 16 (第二引数が省略され、先頭が "0x" の場合は16進数として解釈されます)
console.log(parseInt('1.234')); // 1 (先頭の整数部分だけを Number 型に変換します)
console.log(parseInt('')); // NaN
console.log(parseInt(undefined)); // NaN
console.log(parseInt(null)); // NaN
console.log(parseInt(true)); // NaN
console.log(parseInt(false)); // NaN
console.log(parseInt(new Number(1))); // 1
console.log(parseInt({})); // NaN
console.log(parseInt({valueOf: function (){ return 1; }})); // NaN
console.log(parseInt({valueOf: function (){ return '1'; }})); // NaN
console.log(parseInt({toString: function (){ return '1'; }})) // 1
console.log(parseInt(Symbol())); // TypeError: Cannot convert a Symbol value to a number
parseInt()
は機能的な誤解の多い関数です。
ES3 までの parseInt()
は、第二引数が省略された状態で「0
から始まる数値文字列」を8進数として解釈する仕様でした。
console.log(parseInt('010')); // 8 (ES3 では "0" から始まる数値は8進数として解釈された)
この仕様は多くの人が混乱した為、ES5 で「0
から始まる数値文字列」を10進数として解釈するよう修正が加えられました。
(合わせて、「0から始まる8進数リテラル表記」は Strict Mode で禁止されました)
console.log(parseInt('010')); // 10 (ES5 では "0" から始まる数値も10進数として解釈される)
また、CSSで使われる単位付き数値文字列の単位を落として Number
型へ変換する用途として、parseInt()
は良く使われていました。
console.log(parseInt('10px')); // 10
これは期待通りに動作しますが、先述の「"0" から始まる数値」や「"0x" から始まる数値」の罠があった為、第二引数を必ず指定するよう注意が促されました。
しかしながら、CSSで扱われる px
等の多くの値は小数値を取ることが出来る仕様であり、parseInt()
よりも parseFloat()
がふさわしい事はあまり知られていないようです。
parseFloat() には基数変換機能がない為、第二引数指定漏れによる不具合が誘発されません。
parseFloat()
は第一引数を ToString
によって String
型に変換し、浮動小数点数値である Number
型の値を返します。
parseInt()
と違い、小数を扱えます(整数も扱えます)parseInt()
と違い、基数変換機能はありません
'use strict';
console.log(parseFloat('\n 1 \n')); // 1 (先頭/末尾の空白文字及び行終端文字は無視されます)
console.log(parseFloat('0x10')); // 0 ("0x" で始まる文字を16進数として解釈しません)
console.log(parseFloat('1.234')); // 1.234 (小数を正しく認識します)
console.log(parseFloat('')); // NaN
console.log(parseFloat(undefined)); // NaN
console.log(parseFloat(null)); // NaN
console.log(parseFloat(true)); // NaN
console.log(parseFloat(false)); // NaN
console.log(parseFloat(new Number(1))); // 1
console.log(parseFloat({})); // NaN
console.log(parseFloat({valueOf: function (){ return 1; }})); // NaN
console.log(parseFloat({valueOf: function (){ return '1'; }})); // NaN
console.log(parseFloat({toString: function (){ return '1'; }})) // 1
console.log(parseFloat(Symbol())); // TypeError: Cannot convert a Symbol value to a string
Number.parseInt()
は parseInt()
と同じ関数を返します。
この関数は ECMAScript 2015 (ECMA-262 6th Edition) で定義されました。
Number.parseFloat()
は parseFloat()
と同じ関数を返します。
この関数は ECMAScript 2015 (ECMA-262 6th Edition) で定義されました。