uhyohyo.net

JavaScript初級者から中級者になろう

一章第二回 オブジェクトの実体

オブジェクトの作成

前回、「new Object()」という書き方でオブジェクトを作れるということを解説しました。

しかし、別の書き方があります。しかも、この書き方は、最初からオブジェクトにプロパティを持たせることができます。

aa = {
"aaa":"test",
"bbb":123
};

alert(aa.aaa);
alert(aa.bbb);

「test」「123」が表示されます。

1行目〜4行目がオブジェクトをつくっている部分です。

この書き方は、次のようになります。

{
プロパティ名 : 値,
プロパティ名 : 値,
...
}

つまり、「プロパティ名:値」の組を、「,」で区切って並べ、それを「{ }」で囲んでいるというわけです。ちなみに、今回分かりやすく改行していますが、実際は1行でも構いません。といっても、やはり複数行にまたがったほうが分かりやすいです。プロパティ名が「"」で囲まれていますが、実は囲んでも囲まなくても構いません。

オブジェクトの実体

さて、オブジェクトの実体とはどういうことかというと、実はオブジェクトそのものは変数に「代入」されているわけではなく、実体は変数の中ではなく別の所にあるということです。言っていることがとてもややこしいですが、次のサンプルを見ましょう。

var a = 3;
var b = a;
a = 5;
alert(a);
alert(b);

このコードのやっていることは簡単です。まずaに3を代入します。

次にbにaを代入しています。ここで、aは3ですから、bには3が代入されます。

その後、aには5が代入されます。aをアラートで表示すると、aは当然5です。bは、さっき代入された3です。

これはまったく問題ないコードです。それでは、次のコードはどうでしょう。

var a = {"aaa" : 10};
var b = a;
a.aaa = 5;
alert(a.aaa);
alert(b.aaa);

似たようなことを、オブジェクトを使ってしています。

まず、aに「プロパティaaaを持つオブジェクト」を代入しています。

そして、bにaを代入しています。その後、a.aaaに5を代入しています。

ここで、a.aaaを表示すると、さっき代入した5です。

これはいいですが、次にb.aaaを表示すると、なんと5が表示されます。プロパティaaaが10のaをコピーしてbに代入したから、b.aaaは10のはずです。しかし、5が表示されたのです。

ここに、「実体は代入されていない」ということが関係しています。普通の変数と、オブジェクトが入った変数の違いを図で説明してみます。

変数の複製変数Aにある値が代入されています。

「変数B = 変数A」のようにすると、変数Bに変数Aと同じものが代入されますが、このとき中身が複製されます

変数Aと変数Bには、同じ値でも別々に入っているので、変数Aに別の値を代入しても変数Bはそのままです。

参照の複製一方、オブジェクトの場合はどうでしょう。図の一番上は、変数Aにオブジェクトを代入したときの状態です。 A = {"aaa" : 10};プロパティはaaaを持っていますね。

しかし、図ではオブジェクトは右のほうにあり、実際に変数Aに入っているのは「参照」です(実はこれも完璧に正しい表現ではないらしいですが、これで十分でしょう)。

そして、参照からは矢印が出て、オブジェクトを指しています。下の2つの参照からは矢印が出てませんが、見にくいので省略しているだけで、実際には全てオブジェクトを指しています。

さて、「参照」は、「このオブジェクトはここにあります」ということを表すものです。つまり、本当は、オブジェクトはJavaScriptからは直接触れないところにあって、それを変数に代入された参照を通していじっているということです。

だから、上のサンプルのa.aaa = 5;は、正確には「aが表す(参照する)オブジェクトにあるプロパティaaaに5を代入する」ということです。

だから、aが参照するオブジェクトのプロパティaaaに5が代入されるわけです。

さて、これをb = a;のようにして複製したとき、どうなるでしょうか。

複製されるのは参照です。オブジェクトそのものは複製されません。参照が複製されるということは、当然同じオブジェクトを表すということです。

だから、aもbも表すオブジェクトは同じになり、その結果、aのプロパティaaaをいじろうがbのプロパティaaaをいじろうが結局は同じオブジェクトをいじっていたということです。

つまり、上のサンプルで「b.aaa」が5になっていたのは、「a.aaa」に5を代入した、つまり、a(とb)が表すオブジェクトのプロパティaaaに5を代入したからなのです。

これはなかなか実際的な話です。「b = a;」のようにしてオブジェクトそのものを複製した気になって、変な動作をしてしまい困り果ててしまうということはありがちです。

ちなみに、既にあるオブジェクトへの参照が代入されているaに、新たにa = new Object();のようにした場合、その新しいオブジェクトへの新しい参照が代入され、もともと参照していたオブジェクトとの関係は切れてしまいます。

オブジェクトとプリミティブ

オブジェクトとは、変数に代入したとき、その実体ではなく参照が代入されるというものでした。

それに対し、いままでこの解説では「値」と呼んでいた、実体がそのまま代入されるものをプリミティブ(プリミティブ値)といいます。

「3」とか「"aaaaaaaaa"」とか「true」「false」とかです。ちなみに、プリミティブにも数値とか文字列とか真偽値とか種類がありますが、この種類を「型」といいます。