除了像 number 和 string 這類原始型別之外,JavaScript 還有一種很重要的資料型態叫 object。
物件是鍵值對的集合。
因此,它們的用途和其他語言中常說的映射或字典相同。
在其他語言裡,映射中的所有值通常都必須是相同的資料型態。
在 JavaScript 裡,只有鍵的型別受到限制:它必須是 string。
同一個物件裡的值可以有不同的型別。
它們可以是像數字這樣的原始型別,也可以是陣列、其他物件,甚至是函式。
這讓物件變得非常有彈性,也讓它們成為 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': '...',
};
要取得某個鍵對應的值有兩種方式:點記法和中括號記法。
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
使用點記法這種簡寫方式,跟省略引號有一樣的限制。 只有在鍵符合識別字命名規則時才能使用。
你可以用賦值運算子 = 新增或修改值。
同樣地,點記法和中括號記法都適用。
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'];
你可以用 hasOwnProperty 方法檢查某個鍵是否存在於物件中。
const obj = { greeting: 'hello world' };
obj.hasOwnProperty('greeting');
// => true
obj.hasOwnProperty('age');
// => false
有一種特別的 for...in 迴圈可以疊代物件中的所有鍵。
const obj = {
name: 'Ali',
age: 65,
};
for (let key in obj) {
console.log(key, obj[key]);
}
// name Ali
// age 65
為了避免難以察覺的錯誤,你應該永遠假設 for...in 迴圈走訪鍵的順序是任意的。
另外也要注意,for...in 的疊代會包含繼承的鍵。
在這個練習中,你要實作一套方式,來記錄你當地遊戲機台店裡最受歡迎遊戲的高分。
你需要實作 5 個函式,它們大多和操作一個存放高分的物件有關。
建立一個函式createScoreBoard,它會建立一個物件,用來當作高分板。
這個物件的鍵會是玩家的名稱,值則是他們的分數。
為了測試,你要直接在物件裡加入一筆資料。
這筆初始資料應該包含玩家名稱The Best Ever和分數1000000。
createScoreBoard();
// returns an object with one initial entry
要把玩家加入高分板,請定義函式addPlayer。
它接受 3 個參數:
在加入新玩家之後,這個函式會回傳傳入的同一個高分板物件。
addPlayer({ 'Dave Thomas': 0 }, 'José Valim', 486373);
// => {'Dave Thomas': 0, 'José Valim': 486373}
如果玩家違反遊戲機台店的規則,就會被手動從高分板移除。
定義removePlayer,它接受 2 個參數:
這個函式應該從板上移除指定玩家的資料,然後回傳該板。 如果該玩家原本就不在板上,板子不應該有任何變動,直接原樣回傳即可。
removePlayer({ 'Dave Thomas': 0 }, 'Dave Thomas');
// => {}
removePlayer({ 'Dave Thomas': 0 }, 'Rose Fanaras');
// => { 'Dave Thomas': 0 }
如果玩家在遊戲機台店又完成了一局,就會有一定數量的分數加到板上先前的分數。
實作updateScore,它接受 3 個參數:
這個函式應該在更新完成後回傳該高分板。
updateScore({ 'Freyja Ćirić': 12771008 }, 'Freyja Ćirić', 73);
// => {"Freyja Ćirić", 12771081}
遊戲機台店在週一會另外維護一份高分板。 當天結束時,那份板上的每位玩家都會額外獲得 100 分。
實作函式applyMondayBonus,它接受一個高分板。
這個函式會為板上列出的每位玩家加上獎勵分數,然後回傳該板。
const scoreBoard = {
'Dave Thomas': 44,
'Freyja Ćirić': 539,
'José Valim': 265,
};
applyMondayBonus(scoreBoard);
// => { 'Dave Thomas': 144, 'Freyja Ćirić': 639, 'José Valim': 365 }