jsのプリミティブな型について

JavaScriptのプリミティブな型についての備忘録です。


(今回のテーマ)
以下の違いについて

var text = "hoge";
// 1)
String(text);
// 2)
new String(text);


1) String()

  • 戻り値はprimitiveな値
  • プロパティが要求されたときは、そのラッパーのオブジェクトのプロパティを返す
  • 値はimutableである

2) new String()

  • 戻り値はobject
  • valueOfメソッドで、そのプリミティブな値を返す
  • mutableである(自身を更新可能)
  • 状態(独自なプロパティ)を持てる

サンプルコードを書いてみますと、こういう感じです。

// リテラル表記
var a = "hoge";
// String関数で呼び出した場合
var b = String("hoge");
// Stringコンストラクタとして呼び出した場合
var c = new String("hoge");

typeof a;
// "string"

typeof b;
// "string"

typeof c;
// "object"

a["original"] = "foo";
a["original"];
// undefined
// "original"はa(primitiveなString)についてのラッパーのプロパティとして呼ばれたので、aに対しては設定されない

b["original"] = "foo";
b["original"];
// undefined
// aの場合に同じ

c["original"] = "foo";
c["original"];
// "foo"
// cはobjectなので、任意のプロパティが設定できる

// aとbは本質的に同じ

var d = new String("hoge");

d == a;
// true
// 型変換が行われて、どちらもString型になる

d === a;
// false
// 型が異なる

b === c;
// false
// 保持しているプリミティブな値は同じだが、オブジェクトが異なる

b == d;
// false
// オブジェクト同士なので、型変換が行われない

a.constructor;
// String
// aのラッパー(new String(a))のconstructorを返す

b.constructor;
// String
// aに同じ

c.constructor;
// String
// Stringコンストラクタでnewされたので、Stringを返す

といったところですか。


そもそも、重要になってくるのが、プロパティの参照順序です。
自身が指定したプロパティを持っていない場合、参照する順序は以下の順ようになります。


1) 自身がprimitiveな値である場合
自身のラッパのオブジェクトのプロパティを参照する

"hoge".valueOf(); // の場合
// "hoge"
// 自身のラッパオブジェクトのプロパティをたどる(存在しないので、さらにそのprototypeをたどる)
// (new  String("hoge")).valueOf(); と等価

(222).constructor;
// Number
// 自身のラッパオブジェクトのプロパティをたどる(存在しないので、さらにそのprototypeをたどる)
// (new Nunber(222)).constructor; と等価

2) 自身がオブジェクトである場合

({hoge: "foo"}).hoge;
// 自身がプロパティを持っている場合、自身のプロパティを返す

({}).toString();
// 自身がプロパティを持っていない場合、そのprototypeのプロパティをたどる
// "[object Object]"


この「自身のラッパのオブジェクトのラッパをたどる」挙動は、以下のようなメソッドを作成すると確認できます。

Object.prototype.self = function() {
    return this;
}

typeof ("hoge").self();
// "object"

("hoge").self().valueOf();
// "hoge"

たしかに、thisにはobjectが入ってきていますね。


JavaScriptでは、String、Number、Booleanがprimitiveな値として存在します。
比較演算ではこのあたりの挙動を注意しておく必要があるかなーと思いました。