Hatena::Groupsubtech

冬通りに消え行く制服ガールは、夢物語にリアルを求めない。

 | 

Dec 12, 2007 (Wed)

toSource と uneval の出力からわかる Object と Primitive 01:37

ためしてみるとすぐわかる違い。前提として、JavaScript では「全てオブジェクトというわけではない」ことを覚えておく必要があります (Ruby との違い)。

uneval("foo");
//=> "\"foo\""

"foo".toSource();
//=>  "(new String(\"foo\"))"

なぜこのような違いが生まれるか、というと 11.2.1 プロパティアクセス演算子 (Property Accessors) にある

生成規則 MemberExpression : MemberExpression [ Expression ] は次のように評価される:

  1. MemberExpression を評価。
  2. GetValue(Result(1)) を呼出す。
  3. Expression を評価。
  4. GetValue(Result(3)) を呼出す。
  5. ToObject(Result(2)) を呼出す。
  6. ToString(Result(4)) を呼出す。
  7. 基準オブジェクトが Result(5) でプロパティ名が Result(6) である Reference 型の値を返す。

の ToObject(Result(2)) がキモです。

JavaScript において

"foobar"

typeof "foobar" //=> "string"

は、typeof すればわかるように Primitive な String 型であって、String オブジェクトのインスタンス (Object 型) ではありません。プロパティアクセス演算子が使われると、そのつど String オブジェクトへ変換されます。

これは以下のようにすればすぐわかります。

String.prototype.returnThis = function () { return this };
typeof "foobar".returnThis(); //=> "object"

"foobar".returnThis() === "foobar".returnThis(); //=> false

レシーバは "foobar" にみえますが、上の結果と違っています。これはプロパティアクセス演算子の作用で ToObject された結果が this として渡されているからです。(ToObject は処理系の内部関数なので JS から直接はよべません)

ここでなんとなく気付くと思いますが、this は Object 型以外の型には絶対になりません。this を明示して渡せる call や apply でさえ this に対しては ToObject で変換がかかります。

そうなると、Object に変換されるまえの、Primitive な値がほしいときに (そんなケースあんまりありませんが)、ちょっと困るので、そういうときに valueOf() をつかいます。valueOf() って説明だけ読みとなにがしたいのがさっぱりわかりませんが、こいつを使ってやることで、本来のレシーバ (のようにみえる値) をとることができます。

"foobar".valueOf() //=> "foobar"

この valueOf() はどんなオブジェクトにも存在するので安心して本来のレシーバを取得することができます。(Primitive 値のラッパオブジェクトでは Primitive 値になるし、そうでなければ単に this をかえすだけです)

valueOf には Date オブジェクトみたいに this 以外をかえすのもあります。

 | 
Commented
Calendar
2006 07 08 09 10 11 12
2007 01 02 03 04 05 06 07 08 09 10 11 12
2008 01 02 03 04 05