JavaScript Object (物件)

JavaScript 物件 (object) 是一個複合資料型態 (composite data type),可以儲存不定數量的鍵值對 (key-value pairs),而一組鍵值對我們稱做物件的一個屬性 (property)。一個屬性的值 (value) 可以是任何資料型態 (也可以是函數);而屬性的名稱 (key / name) 是一個字串型態。

物件宣告 (Creating Objects)

有兩種方式可以建立一個物件:

Object Constructor (物件建構式)

用 new 關鍵字加上 Object() 來宣告一個物件:

const myObj = new Object();

Object Literal (物件實字)

Object literal 是最常用也最方便的語法,用 {} 就可以宣告一個物件:

const myObj = {};

物件的屬性 (Object Properties)

存取屬性 (Accessing Properties)

我們可以用 . (Dot notation) 或 [] (Bracket notation) 來存取屬性。

  1. Dot notation (.):最常用,語法簡潔。
  2. Bracket notation ([]):當屬性名稱包含特殊符號、空格,或是動態變數時使用。
const myObj = {
  color: 'blue',
  'user name': 'Mike', // 包含空格的屬性名稱
};

// Dot notation
console.log(myObj.color); // 'blue'

// Bracket notation
console.log(myObj['color']); // 'blue'
console.log(myObj['user name']); // 'Mike'

// 動態存取
const propName = 'color';
console.log(myObj[propName]); // 'blue'

刪除屬性 (Deleting Properties)

使用 delete 關鍵字可以刪除物件的特定屬性。

const person = { name: 'Mike', age: 30 };
delete person.age;

console.log(person); // { name: 'Mike' }

檢查屬性是否存在

要檢查一個屬性是否存在於物件中,可以使用 in 運算子或 Object.hasOwn()(推薦,比 hasOwnProperty 更安全)。

const person = { name: 'Mike' };

console.log('name' in person); // true
console.log('age' in person); // false

// 現代寫法 (ES2022)
console.log(Object.hasOwn(person, 'name')); // true

Optional Chaining (可選串連) ?.

在存取深層巢狀物件時,為了避免 Uncaught TypeError: Cannot read properties of undefined 錯誤,我們可以使用 ?.。如果屬性不存在,它會短路並回傳 undefined,而不會報錯。

const user = {
  name: 'Mike',
  // address 屬性不存在
};

// 舊式寫法
const city = user.address ? user.address.city : undefined;

// 現代寫法
const city2 = user?.address?.city; // undefined (不會報錯) // 變數名稱改為 city2 避免重複宣告

物件的方法 (Object Methods)

物件的屬性值如果是一個函數,我們稱它是物件的方法 (method)。

const person = {
  firstName: 'Mike',
  lastName: 'Lee',
  // 使用 this 關鍵字存取物件本身的屬性
  fullName: function () {
    return this.firstName + ' ' + this.lastName;
  },
};

console.log(person.fullName()); // "Mike Lee"

ES6 Object Literal Extensions (新語法)

ES6 提供了讓物件寫法更簡潔的語法糖。

1. 屬性簡寫 (Property Shorthand)

當屬性名稱與變數名稱相同時,可以省略冒號與值。

const name = 'Mike';
const age = 30;

// 舊寫法
const person1 = { name: name, age: age };

// 新寫法
const person2 = { name, age };

2. 方法簡寫 (Method Shorthand)

定義方法時,可以省略 function 關鍵字。

const person = {
  name: 'Mike',
  // 舊寫法
  sayHello: function () {
    console.log('Hello!');
  },
  // 新寫法
  sayHi() {
    console.log('Hi!');
  },
};

3. 計算屬性名稱 (Computed Property Names)

允許使用表達式 [] 來動態產生屬性名稱。

const prefix = 'user';
const id = 123;

const user = {
  [prefix + '_' + id]: 'Mike', // 屬性名稱變為 "user_123"
};

console.log(user.user_123); // "Mike"

物件的遍歷與操作 (Looping & Manipulation)

遍歷物件

  1. for...in 迴圈:遍歷所有可枚舉屬性(包含繼承的)。
  2. Object.keys():回傳所有 Key 的陣列。
  3. Object.values():回傳所有 Value 的陣列。
  4. Object.entries():回傳 [Key, Value] 的陣列。
const person = { name: 'Mike', age: 30 };

// Object.keys
Object.keys(person).forEach((key) => {
  console.log(key, person[key]);
});
// 輸出:
// name Mike
// age 30

合併與複製 (Merging & Cloning)

在現代 JavaScript 中,我們通常使用 Spread Operator (...) 進行淺拷貝 (Shallow Copy) 或合併。

const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };

// 合併物件 (後面的屬性會覆蓋前面的)
const merged = { ...obj1, ...obj2 };
// { a: 1, b: 3, c: 4 }

// 複製物件
const clone = { ...obj1 };
注意:Spread Operator 只是「淺拷貝」。如果物件內還有巢狀物件,巢狀物件仍然是 reference 參考,修改它會影響到原始物件。

JavaScript 內建物件

JavaScript 還有許多特殊的內建物件: