JavaScriptには、numberやstringのようなプリミティブ型のほかに、objectという重要なデータ型があります。
オブジェクトは、キーと値のペアの集まりです。
そのため、他の言語でマップや辞書と呼ばれているものとして使うことができます。
他の言語では、マップの中の値がすべて同じデータ型でなければならないことがよくあります。 JavaScriptで制限されているのはキーの型だけです。キーは文字列でなければなりません。 1つのオブジェクトの中の値は、それぞれ違う型でもかまいません。 数値のようなプリミティブ型だけでなく、配列や、別のオブジェクト、関数さえも入れられます。 このおかげでオブジェクトはとても柔軟で、JavaScriptのオブジェクト指向プログラミング(OOP)にとっても中心的な存在になっています。
以下では、集まりやマップとしてのオブジェクトに焦点を当てます。オブジェクトのそのほかの使い方は別の概念で扱います。たとえばクラスを参照してください。
オブジェクトリテラルは、波括弧を使って作成します。 最初からいくつかのエントリー(キーと値のペア)を直接含めることもできます。 その場合は、まずキーを書き、そのあとにコロンと値を続けます。
const emptyObject = {};
const obj = {
favoriteNumber: 42,
greeting: 'Hello World',
useGreeting: true,
address: {
street: 'Trincomalee Highway',
city: 'Batticaloa',
},
fruits: ['melon', 'papaya'],
addNumbers: function (a, b) {
return a + b;
},
};
最後のエントリーのあとに付くカンマは、JavaScriptでは省略できます。 これを使う利点についてはこちらで読むことができます。
キーは文字列のはずなのに、なぜ引用符で囲まれていないのだろうと不思議に思うかもしれません。 これは省略記法です。 キーがJavaScriptの識別子の命名規則に従っているなら、引用符は省略できます。 名前に特殊文字を含むキーには、通常の文字列の記法を使う必要があります。
const obj = {
'1keyStartsWithNumber': '...',
'key/with/slashes': '...',
'key-with-dashes': '...',
'key with spaces': '...',
'#&()[]{}èä樹keyWithSpecialChars': '...',
};
オブジェクトを宣言するときに、すでにある変数を追加したいことがよくあります。
そのままだとname: nameのようなキーと値のペアを書くことになります。
JavaScriptには、代わりにnameとだけ書ける省略記法があります。
オブジェクトに関数を定義するときの省略記法もあり、そこではコロンとfunctionキーワードを省略できます。
const x = 1;
const y = 2;
const obj = {
x: x,
y: y,
calcSum: function (a, b) {
return a + b;
},
};
// Can be shortened to ...
const obj = {
x,
y,
calcSum(a, b) {
return a + b;
},
};
変数に入っているキー名や、式から得られるキー名でオブジェクトリテラルを作りたい場合は、その変数や式を角括弧で囲む必要があります。
const key = 'greeting';
const obj = {
[key]: 'hello world',
};
console.log(obj);
// => { greeting: 'hello world' }
あるキーの値を取得する方法は2つあります。ドット記法と括弧記法です。
const obj = { greeting: 'hello world' };
obj.greeting;
// => hello world
obj['greeting'];
// => hello world
// Bracket notation also works with variables.
const key = 'greeting';
obj[key];
// => hello world
省略記法としてのドット記法には、引用符を省略する場合と同じ制限があります。 キーが識別子の命名規則に従っているときだけ使えます。
オブジェクトに存在しないキーを取得しようとすると、JavaScriptはundefinedを返します。
詳しくはNullとUndefinedを参照してください。
入れ子になったオブジェクトから値を取得したいときは、キーをつなげて書くことができます。
const obj = {
address: {
street: 'Trincomalee Highway',
city: 'Batticaloa',
},
};
obj.address.city;
// => 'Batticaloa'
obj['address']['city'];
// => 'Batticaloa'
// Notations can also be mixed.
obj.address['city'];
// => 'Batticaloa'
代入演算子=を使うと、値を追加したり変更したりできます。
ここでもドット記法と括弧記法が使えます。
const obj = { greeting: 'hello world' };
obj.greeting = 'Hi there!';
obj['greeting'] = 'Welcome.';
obj.newKey1 = 'new value 1';
obj['new key 2'] = 'new value 2';
const key = 'new key 3';
obj[key] = 'new value 3';
deleteキーワードを使うと、オブジェクトからキーと値のペアを削除できます。
const obj = {
key1: 'value1',
key2: 'value2',
};
delete obj.key1;
delete obj['key2'];
存在しないキーに対してはundefinedが返りますが、キーにundefinedを設定してもエントリーは削除されないことに注意してください。
代わりに必ずdeleteを使ってください。
hasOwnPropertyメソッドを使うと、あるキーがオブジェクトに存在するかどうかを確認できます。
const obj = { greeting: 'hello world' };
obj.hasOwnProperty('greeting');
// => true
obj.hasOwnProperty('age');
// => false
hasOwnPropertyは継承されたキーに対してfalseを返します。
通常はこれが望ましい動作です。
継承されたキーも存在確認に含めたい場合は、代わりにin演算子を使えます。
オブジェクトのすべてのキーを繰り返し処理するための、特別なfor...inループがあります。
const obj = {
name: 'Ali',
age: 65,
};
for (let key in obj) {
console.log(key, obj[key]);
}
// name Ali
// age 65
for...inは、キーがオブジェクトに現れた順、または追加された順(挿入順)で必ずたどるように思えるかもしれません。
しかし、これに頼ってはいけません。挿入順とは違う順序になる特別な場合があるからです。
順序はいつでも任意だと考えてコードを書いてください。
信頼できる順序が必要なら、オブジェクトの代わりにMapや入れ子の[配列][concept-arrays]を使ってください。
for…inループには、オブジェクトが継承されたキーを持っている場合の落とし穴があります。
それらのキーもfor…inループにたどられます。
通常はそれを避けたいので、以下に示すようにスキップする必要があります。
for (let key in obj) {
if (!obj.hasOwnProperty(key)) {
continue;
}
// ...
}
JavaScriptにはfor...ofループもあり、たとえば配列を繰り返し処理するのに使います。
for...inとfor...ofは互換性がないことに注意してください。詳しくはMDNのドキュメントを参照してください。
組み込みオブジェクトのObjectには、あるオブジェクトのキー、値、エントリーをすべて配列として取得するための補助メソッドが用意されています。
const obj = {
name: 'Ali',
age: 65,
};
Object.keys(obj);
// => [ 'name', 'age' ]
Object.values(obj);
// => [ 'Ali', 65 ]
Object.entries(obj);
// => [ [ 'name', 'Ali' ], [ 'age', 65 ] ]
JavaScriptの空のオブジェクトは完全には空ではないことに気づいたかもしれません。
たとえば、hasOwnPropertyメソッドや、toStringのようなその他のメソッドを持っています。
通常は問題になりませんが、本当に空のオブジェクトを作る必要があるときは、Object.create(null)で作成できるnullオブジェクトを使ってください。