はじめに
別の記事を読んでいて、プリミティブ型の暗黙的な型変換について誤解されているようなコードがちょっと気になったので、簡単に解説してみたいと思います。
このコード分かりますか?
まず最初に質問です。以下は正常に動作するコードです。このコードが(3)で最後に出力する値は何でしょうか?また、その理由はなぜでしょうか?
答えはすぐ下にありますが、まずは答えを見ないで考えてください。
//このコードは非strict modeの場合のみ動作します。strict modeの場合は(2)でTypeErrorとなります。
var num = 100; // (1)
num.question = "What is this code ?"; // (2)
console.log(num.question); // (3)
答え
(3)で、console.log(num.question)の出力結果はundefinedとなります。
理由
(2)ではnumは自動的にラッパーオブジェクトに変換され、変換されたオブジェクトのプロパティ(question)に文字列が代入されます。(3)でも同様にnumはラッパーオブジェクトに変換されます。これは(2)とは別のラッパーオブジェクトです。そのため、そのプロパティquestionはundefinedとなります。もし,
このコードを意図した(numにプロパティを追加したい)ものにしたければ、(1)では明示的にラッパーオブジェクトを生成する必要があります(こちらに載せてます)。
解説
JavaScriptではプリミティブ型に対するプロパティアクセスが発生した場合、対応するラッパーオブジェクトに暗黙的に型変換が行われます。
- (1)では、変数
numは数値100を代入しているのでプリミティブ型(number型)となります。 - (2)では、
numのプロパティquestionにアクセスしていますが、numはプリミティブ型なので、自動的にラッパーオブジェクトであるNumberに型変換されます。 - 変換後のオブジェクトのプロパティ(
question)に文字列が代入されます。 - (3)では、
numのプロパティにアクセスしていますが、ここでも自動的にNumberオブジェクトに型変換されます。 - 4.で生成されたオブジェクトのプロパティ(
question)は存在しないので、undefinedとなります。
ここで、注目して欲しいのは、2.で型変換により生成されたオブジェクトと4.で生成されたオブジェクトは別物だということです。
この暗黙的な型変換をコードで表すと以下のようになります。
var num = 100;
var _numWrapper1 = new Number(num); // ラッパーオブジェクトに変換。
_numWrapper1.question = "What is this code ?";
var _numWrapper2 = new Number(num); // ラッパーオブジェクトに変換。上記のオブジェクトとは別オブジェクト。
console.log(_numWrapper2.question);
ここで、_numWrapper1と_numWrapper2は別のオブジェクトであることに注意してください。
応用例
上記のように数値型だけではなく、文字列やブーリアン型などの他のプリミティブ型でも型変換は行われます。
var s = "Hello, world!";
console.log(s.length); // 13
console.log(s.toUpperCase()); // メソッドも呼び出せます。"HELLO, WORLD!"
var n = 10000.123;
console.log(n.toExponential()); // "1.0000123e+4"
var b = true;
console.log(b.toString()); // "true"
このように、プリミティブ型からラッパーオブジェクトへの型変換は自動的に行われるため、以下のように、プリミティブ型をいちいちラッパーオブジェクトに変換する必要はないでしょう。
var s = new String("Hello, world!"); // 自動的に型変換されるので、冗長。
console.log(s.toUpperCase());
ただし、冒頭の質問のように値を永続化したい場合は、以下のように(プリミティブ値にプロパティを追加する是非はおいておいて)ラッパーオブジェクトを使う必要があるでしょう。
var num = new Number(100);
num.question = "What is this code ?";
console.log(num.question); // "What is this code ?";