除了像number和string這類基本資料型態之外,JavaScript 還有另一種重要的資料型態,叫做object。
物件是鍵值對的集合。
因此,它們可以當作其他語言中常說的映射或字典來使用。
在其他語言中,映射裡的所有值通常都必須是相同的資料型態。 在 JavaScript 中,只有鍵的型態受到限制:它必須是字串。 一個物件裡的值可以有各種不同的型態。 它們可以是數字這類基本型態,也可以是陣列、其他物件,甚至函式。 這讓物件非常有彈性,也因此成為 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' }
要取得某個鍵對應的值有兩種方式:點記法和括號記法。
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這類其他方法。
這通常不會造成任何問題,但如果你真的需要建立一個完全空無一物的物件,可以使用 null 物件,它能透過Object.create(null)建立。