uhyohyo.net

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

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

このページの最終更新日:

オブジェクトの作成

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

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

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

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

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

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

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

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

つまり、プロパティ名:値の組を、,で区切って並べ、それを{ }で囲んでいるというわけです。ちなみに、今回分かりやすく改行していますが、実際は1行でも構いません。プログラムで空白や改行の有無で意味が変わる場面はほとんどないのです。とはいっても、やはり複数行にまたがったほうが分かりやすいです。プロパティ名が"で囲まれていますが、実は囲んでも囲まなくても構いません。ただし、変なプロパティ名(ハイフンマイナス-をはじめとする変な記号を含む場合など)の場合は"で囲まないと文法エラーとなります。

なお、この書き方でオブジェクトを表現する方法をオブジェクトリテラルといいます。実際のプログラムではオブジェクトはほぼ全てオブジェクトリテラルで書かれます。new Object()で書く人はほとんどいません。

オブジェクトの性質

オブジェクトは、文字列や数値といった今までの値とは大きく異なる特徴を持ちます。それは、オブジェクトは作成したあとから変更可能 (mutable) な値であるという点です。以下では、これがどういうことなのかを説明します。

まず、次のコードについて考えてみましょう。

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

このコードを実行すると何が表示されるでしょうか。これは引っ掛け問題とかではなく、簡単です。

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

その後、aには5が代入されます。ですから、最後にa,bの順に表示すると「5」「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が表示されます。先ほどと同じように考えると、これはおかしいですね。変数aには{"aaa": 10}が入っていたのだから、次のvar b = a;により変数bにも{"aaa": 10}が入っているように思えます。そのあと変数bはいじっていないのだからb.aaaは10となっていそうなところです。

ここに、先に述べた「オブジェクトは作成したあとから変更可能」ということが関係しています。

実は、この場合、変数aと変数bに入っているのは同じオブジェクトです。いま、1行目のオブジェクトリテラル{"aaa": 10}によって作成されたオブジェクトをオブジェクトOと呼ぶことにしましょう。変数aにはオブジェクトOが入りました。2行目では、変数bに変数aの中身を代入しています。ということは、変数bに入っているのもオブジェクトOなのです。ポイントは、2つの変数a, bに同じオブジェクトOが入っているということです。

3行目のa.aaa = 5という操作の意味は「aのプロパティaaaに5を代入する」ということでしたが、変数aの中身はオブジェクトOでしたから、これはオブジェクトOのプロパティaaaに5を代入していることになります。

この操作により、オブジェクトOの中身(プロパティaaa)が変わりました。これが、オブジェクトが変更可能ということです。

ここで、bの中身はオブジェクトOであり、オブジェクトOのプロパティaaaはさっきの代入で5に変更されました。これが、b.aaaを表示すると5になる理由です。

結局、ポイントは、var b = a;bにはa同じオブジェクトが入ったことと、そのオブジェクトが変更されたことです。

さらに理解するために、オブジェクトを使わない例をもう一度振り返ってみましょう。

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

この例でも、2行目によって、変数bにはaと同じものが代入されたはずです。ここでは、それは3という数値です。この3という数値を数値Aと呼ぶことにすると、変数aとbには両方とも数値Aが入っていることになります。オブジェクトの場合と異なるのは、数値Aの値は変更されないということです。数値Aが3から4とか5になったりすることはありません。数値Aは永遠に3のままです。

ですから、3行目のa = 5;では、5は別の数値Bであって、それを変数aに入れたということになります。この後、変数bに入っているのはいまだ数値Aですから、bは3ということになります。

これを応用すると、次のような例を書くことができます。

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

こうすれば、{"aaa": 10}というオブジェクトリテラルが2回登場しているのでオブジェクトが2個別々に作られ、それぞれ変数a、変数bに代入されます。よって、変数aの中身と変数bの中身は別のオブジェクトとなり、一方を変更してももう一方に影響することはありません。

以上で説明したように、オブジェクトは変更可能なので、どの変数に入っているオブジェクトが同じなのかということを意識する必要があります。実際のプログラミングでもミスをする人が多い点ですから、気をつけましょう。

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

オブジェクトは、変更可能であるという点で従来われわれが扱ってきた数値や文字列などとは異なっています。これらの、オブジェクト以外の値のことをプリミティブ(プリミティブ値)といいます。プリミティブには、プロパティ等の概念はありません。

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