JavaScript

型の変換

 JavaScript は、必要とする値の型について、非常に柔軟な対応をします。論理値については「論理値」を参照ください。JavaScript が論理値を必要とする場面では、どのような型の値を指定しても、JavaScript が必要な型変換を行います。true と見なす値については true と同じ振る舞いをし、false と見なす値については false と同じ振る舞いをします。他の型についても同様です。例えば、JavaScript が文字列を必要とする場面では、どのような値でも文字列に変換します。数値が必要となる場面では、数値に変換しようとします(変換できない場合には、NaN に変換します)。例をいくつか紹介します。

10 + " objects"
// => "10 objects": 数値の 10 が文字列に変換される。

"7" * "4"
// => 28: 両方の文字列が数値に変換される。

var n = 1 - "x";
// => NaN: 文字列 "x" は数値に変換できない。

n + " objects"
// => "NaN objects": NaN は "NaN" という文字列に変換される。

 JavaScript での型変換について、概要を下表にまとめておきます。太字で記述している部分は、特に注意してください。空欄になっている部分は、変換が不要という意味です。

変換先
文字列 数値 論理値 オブジェクト
undefined
null
"undefined"
"null"
NaN
0
false
false
TypeError 例外
TypeError 例外
true
false
"true"
"false"
1
0
new Boolean(true)
new Boolean(false)
""(空文字列)
"1.2"(数値文字列)
"one"(数値以外の文字列)
0
1.2
NaN
false
true
true
new String("")
new String("1.2")
new String("one")
0
-0
NaN
Infinity
-Infinity
1(有限値、0 以外)
"0"
"0"
"NaN"
"Infinity"
"-Infinity"
"1"
false
false
false
true
true
true
new Number(0)
new Number(-0)
new Number(NaN)
new Number(Infinity)
new Number(-Infinity)
new Number(1)
{}(任意のオブジェクト)
[](空の配列)
[9](要素が数値 1つの配列)
['a'](それ以外の配列)
function(){}(任意の関数)
下記を参照
""
"9"
join()メソッドを使う
下記を参照
下記を参照
0
9
NaN
NaN
true
true
true
true
true

 上表で示したように、基本型から基本型への変換は比較的理解しやすいものです。論理値への変換については、「論理値」を参照ください。文字列への変換は、すべての基本型値に対して明解です。数値への変換だけが少しややこしいものになっています。数値として解釈できる文字列に対しては、その数値に変換されます。数値文字列の前後の空白は無視されます。ただし、数値文字列の前後に、数値リテラルとして使えない文字がある場合は、文字列から数値へ変換すると NaN が返されます。この他にも、true1 に変換され、false と空文字列 "" が 0 に変換されることにも注意してください。

 基本型からオブジェクトへの変換も簡単です。基本型値は、String()Number()Boolean() コンストラクタを明示的に呼び出したかのように、ラッパーオブジェクトに変換されます。ただし、nullundefined は例外です。この 2つの値を、オブジェクトを必要とする場面で使うと、変換は行われず TypeError 例外が発生します。

 オブジェクトから基本型への変換は少し複雑ですので、下記「オブジェクトから基本型への変換」で説明します。

変換と比較

 JavaScript では、柔軟に型変換が行われます。等値演算子 == でも、等しいかどうかの判定が柔軟に行われます。例えば、以下に挙げる比較はすべて true と判定されます。

null == undefined
// この 2つの値は等しいものとして扱われる。

"0" == 0
// 比較する前に、文字列は数値に変換される。

0 == false
// 比較する前に、論理値は数値に変換される。

"0" == false
// 比較する前に、両方のオペランドが数値に変換される。

 別ページで、== 演算子を実行するときに、2つの値が等しいかどうかを判定するために、どのような型変換が行われるのかを詳しく説明します。また、厳密に比較を行う === 演算子の場合には、型変換が行われないことについても紹介します。

 ある値が別の値に変換できるということは、2つの値が等しいという意味ではないということに気をつけてください。例えば、undefined を論理値が必要な場所で使うと、false に変換されます。しかし、これは undefined == false だということではありません。JavaScript の演算子や文では、さまざまな型の値を必要とするので、必要とする型への変換が行われます。if 文の場合は論理値型が必要なので undefinedfalse に変換します。しかし、== 演算子では、論理値型が必要なわけではないので、オペランドを論理値に変換しません。

明示的な型変換

 JavaScript では多くの型変換が自動的に行われますが、明示的に型変換しなければならない場合もあります。また、コードをわかりやすくするために、明示的に型変換したい場合もあるでしょう。

 明示的に型変換を行うには、Boolean()Number()String()Object() 関数を使うのが簡単です。これらの関数は、ラッパーオブジェクトのコンストラクタとして紹介しました。しかし、new 演算子なしで呼び出すと、型変換関数として動作し、上表で紹介したような型変換を行います。

Number("3")
// => 3

String(false)
// => "false": false.toString() でも変換可。

Boolean([])
// => true

Object(3)
// => new Number(3)

 nullundefined 以外の値は、toString() メソッドを持ちます。一般的に、toString() メソッドの戻り値は、String() 関数の戻り値と同じです。また、上表で示したように、nullundefined をオブジェクトに変換しようとすると、TypeError 例外が発生します。しかし、Object() 関数を使う場合には例外は発生しません。この場合は、空オブジェクトが新たに生成され返されるだけです。

 JavaScript の演算子には、暗黙に型変換を行うものがあります。このため、このような演算子を型変換のために使う場合があります。+ 演算子の一方のオペランドが文字列の場合、もう一方のオペランドは文字列に変換されます。単項 + 演算子は、オペランドを数値に変換します。単項 ! 演算子は、オペランドを論理値に変換し、真偽を反転させます。このような暗黙の変換処理を使うために、次のような型変換記法が様々なコードで使われています。

x + ""
// String(x) と同じ。

+x
// Number(x) と同じ。x-0 という表現も使われる。

!!x
// Boolean(x) と同じ。! を 2回記述していることに注意。

 数値を整形したり解釈したりする処理は、プログラムではよく行われる処理です。JavaScript には、数値から文字列への変換や、文字列から数値への変換において整形や解釈を行う関数やメソッドが用意されています。

 Number クラスに定義されている toString() メソッドには、変換対象の基数を引数で指定できます。引数を指定しなかった場合は、10進数に変換されます。2進数から36進数までの間で明示的に基数を指定することができます。次の例を見てください。

var n = 17;

binary_string = n.toString(2);
// "10001" になる。

octal_string = "0" + n.toString(8);
// "021" になる。

hex_string = "0x" + n.toString(16);
// "0x11" になる。

 金融関係のデータや、科学データについて処理する場合は、数値を文字列に変換するときに、小数点の位置や有効数字を制御したいこともあるでしょう。また、指数表現を使うかどうかも指定したくなるかもしれません。Number クラスには、数値を文字列に変換するメソッドが 3つ定義されています。toFixed() メソッドを使えば、数値が文字列に変換され、小数点以下は指定した桁数だけ残されます。このメソッドでは指数表現には変換されません。toExponential() メソッドを使えば、数値は指数表現に変換されます。この指数表現では、整数部が 1桁で、小数点以下に指定された桁数を持つように変換されます(つまり有効桁数は、指定した値より 1つ多くなります)。toPrecision() メソッドを使えば、有効桁数を指定して数値を文字列に変換できます。有効桁数が数値の整数部よりも桁数が少ない場合には、指数表現に変換されます。なお、この 3つのメソッドで数値を文字列へ変換すると、必要に応じて四捨五入や末尾への 0 追加が行われます。次の例を見てください。

var n = 123456.789;

n.toFixed(0);
// "123457"

n.toFixed(2);
// "123456.79"

n.toFixed(5);
// "123456.78900"

n.toExponential(1);
// "1.2e+5"

n.toExponential(3);
// "1.235e+5"

n.toPrecision(4);
// "1.235e+5"

n.toPrecision(7);
// "123456.8"

n.toPrecision(10);
// "123456.7890"

 Number() 型変換関数に対して文字列を引数として渡すと、文字列を整数または浮動小数点リテラルとして解釈しようとします。この関数は 10進数しか処理できません。また、文字列の末尾に数値リテラルとして利用できない文字が続いている場合には解釈できません。parseInt() 関数と parseFloat() 関数(この 2つの関数はメソッドではなく、グローバル関数です)は、もう少し柔軟に対応します。parseInt() 関数は整数だけしか解析しませんが、parseFloat() 関数は整数と浮動小数点数の両方を解析します。先頭が「 0x 」または「 0X 」の場合、parseInt() 関数はその数値を 16進数と解釈します。

 ECMAScript 3 仕様では、数値が 0 から始まる場合(ただし「 0x 」でも「 0X 」でもない場合)、parseInt() 関数は、その数値を 10進数として解釈しても、また 8進数と解釈しても良いことになっています。このように振る舞いが決まっていないので、0 から始まる数字を数値に変換するために parseInt() を使う場合は、基数を指定するようにしてください。ECMAScript 5 仕様では、基数として 2番目の引数に 8 を明示的に指定した場合にのみ、parseInt() 関数は 8進数として解釈します。

 parseInt()parseFloat() 関数も、文字列の前の空白は無視し、できるだけ多くの数値文字列を解釈し、その後の文字も無視します。文字列のうち、最初の空白以外の文字が数値として解釈できない文字の場合には、NaN が返されます。いくつか例を紹介します。

parseInt("3 blind mice")
// => 3

parseFloat(" 3.14 meters")
// => 3.14

parseInt("-12.34")
// => -12

parseInt("0xFF")
// => 255

parseInt("0xff")
// => 255

parseInt("-0XFF")
// => -255

parseFloat(".1")
// => 0.1

parseInt("0.1")
// => 0

parseInt(".1")
// => NaN: 整数の場合、「 . 」が先頭にくることはない。

parseFloat("$72.47");
// => NaN: 数値は「 $ 」が先頭にくることはない。

 parseInt() 関数は、2番目の引数として基数を指定できます。指定できる値は、2 から 36 までです。以下の例を見てください。

parseInt("11", 2);
// => 3 (1*2 + 1)

parseInt("ff", 16);
// => 255 (15*16 + 15)

parseInt("zz", 36);
// => 1295 (35*36 + 35)

parseInt("077", 8);
// => 63 (7*8 + 7)

parseInt("077", 10);
// => 77 (7*10 + 7)

オブジェクトから基本型への変換

 オブジェクトから論理値への変換は簡単です。すべてのオブジェクトは、配列や関数も含めて true に変換されます。ラッパーオブジェクトも true に変換されます。つまり、new Boolean(false) も基本型ではなくオブジェクトなので、true に変換されます。

 オブジェクトから文字列へ変換や、オブジェクトから数値への変換は、変換対象のオブジェクトのメソッドを呼び出すことで行います。JavaScript オブジェクトには、変換を行う 2つの異なるメソッドが存在します。また、これから説明する特殊な場合があるので、型変換は理解しにくくなっています。ここで紹介する文字列と数値への変換規則は、ネイティブオブジェクトにだけ適用されます。例えば、Webブラウザで定義されているようなホストオブジェクトについては、独自にアルゴリズムを使って数値や文字列に変換されます。

 すべてのオブジェクトは、変換メソッドを 2つ持ちます。最初に紹介するのは、toString() メソッドです。このメソッドは、オブジェクトを表す文字列を返します。デフォルトの toString() メソッドは、あまり意味のある値を返しません。例を示します。

({x:1, y:2}).toString()
// => "[object Object]"

 多くのクラスでは、そのクラス用に toString() メソッドを定義しています。例えば、Array クラスの toString() メソッドは、配列の各要素を文字列に変換し、カンマで区切って結合した文字列を返します。Function クラスの toString() メソッドは、処理系で定義されている関数表現を返します。実際には、ユーザ定義の関数は JavaScript のソースコード文字列に変換されるのが普通です。Date クラスが定義している toString() メソッドは、人が見てわかるような(かつ JavaScript で解釈できる)日付/時刻文字列を返します。RegExp クラスの toString() メソッドは、RegExp オブジェクトを、RegExp リテラルのような文字列に変換します。以下にいくつか例を挙げます。

[1,2,3].toString()
// => "1,2,3"

(function(x) { f(x); }).toString()
// => "function(x) {\n f(x);\n}"

/\d+/g.toString()
// => "/\\d+/g"

new Date(2010,0,1).toString()
// => "Fri Jan 01 2010 00:00:00 GMT-0800 (PST)"

 もう 1つの型変換メソッドは、valueOf() メソッドです。このメソッドは、toString() ほどはっきりとは定義されていません。基本的には、(もしも、そのような基本型値があるのであれば)オブジェクトを、そのオブジェクトを表す基本型値に変換するのが仕事です。オブジェクトは複合型の値なので、実際には、大半のオブジェクトは 1つの基本型で表現することはできません。このため、デフォルトの valueOf() メソッドは、基本型の値を返すのではなく、単純にオブジェクトそのものを返します。ラッパークラスの valueOf() メソッドは元の基本型値を返します。また、配列や関数、正規表現クラスは、デフォルトメソッドをを継承しています。つまり、これらの型のインスタンスに対して valueOf() を呼び出すと、オブジェクトそのものが返されるだけです。なお、Date クラスの valueOf() メソッドは、日付を内部表現で返します。その内部表現とは、1970年1月1日からの時間をミリ秒単位で表したものです。以下に例を示します。

var d = new Date(2010, 0, 1);
// 2010年1月1日(太平洋標準時)

d.valueOf()
// => 1262332800000

 ここまで、toString()valueOf() メソッドについて紹介しました。これで、オブジェクトから文字列への変換と、オブジェクトから数値への変換を説明する準備が整いました。ただし、JavaScript には、ここで紹介するのとは異なる方法でオブジェクトから基本型への変換が行われる場合があることに注意しておいてください。このような特殊な場合については、このページの最後に説明します。

 オブジェクトを文字列に変換する場合、JavaScript は次の 3つの手順を踏みます。

 オブジェクトを数値に変換する場合、JavaScript は同様の手順を踏みます。ただし、valueOf() メソッドから利用していきます。

 ここで紹介したオブジェクトから数値への変換の流れを見れば、なぜ空の配列が数値の 0 に変換されるのか、また、要素を 1つしか持たない配列も数値に変換されるのかが理解できるでしょう。配列は、デフォルトの valueOf() メソッドを継承するので、このメソッドは基本型値ではなくオブジェクトを返します。したがって、配列を数値に変換する場合は、toString() メソッドが使われます。空の配列は空の文字列に変換されます。そして、空の文字列は数値の 0 に変換されます。要素が 1つだけの配列の場合は、その要素と同じ文字列に変換されます。配列が 1つの数値だけを保持するのであれば、その数値が文字列に変換された後、再度数値に戻されます。

 JavaScript の + 演算子は、数値の加算と、文字列の連結を行います。オペランドの一方がオブジェクトの場合、ほかの算術演算で利用するオブジェクトから数値への変換ではなく、オブジェクトから基本型への変換処理を行います。== 等値演算子の場合も同じです。オブジェクトを基本型値と比較する場合、オブジェクトから基本型への変換処理を行います。

 + や == で使われるオブジェクトから基本型への変換処理では、Date オブジェクトの場合にも特殊な処理が行われます。Date クラスは、コア JavaScript 言語において、文字列や数値への意味のある変換処理が定義されている唯一のクラスです。オブジェクトから基本型への変換処理では、Date オブジェクト以外のオブジェクトについては、オブジェクトから数値への変換処理を使います(つまり、valueOf() から使います)。一方で、Date オブジェクトに対しては、オブジェクトから文字列への変換処理を使います(つまり、toString() から使います)。しかし、変換処理は先ほど説明した処理と完全に同じというわけではありません。valueOf()toString() から返された基本型値は、数値や文字列に強制的に変換されることなく、そのまま使われます。

 < 演算子などの比較演算子でも、== と同様に、オブジェクトから基本型への変換が行われます。ただし、Date オブジェクトでも特別な処理は行われません。オブジェクトはすべて、まず valueOf() を使って変換し、変換できない場合には toString() を使います。基本型値が得られた場合は、数値や文字列に変換することなく、そのまま使います。

 +==!= と関係演算子のみ、文字列から基本型への変換が行われます。ほかの演算子では、もっと明示的に必要とされる型に変換します。また、Date オブジェクト用の特殊な処理も行われません。例えば、- 演算子はオペランドを数値に変換します。以下に、Date オブジェクトに対して、+-== を使った時の振る舞いの例を紹介します。

var now = new Date();
// Date オブジェクトを生成する。

typeof (now + 1)
// => "string": + は日付を文字列に変換する。

typeof (now - 1)
// => "number": - はオブジェクトを数値型へ変換する。

now == now.toString()
// => true: 暗黙の文字列変換と、明示的な文字列変換。

now > (now -1)
// => true: > は Date を数値に変換する。