2021 年 6 月 27 日

Object.keys、values、entries

讓我們暫時離開個別資料結構,來談談如何反覆運算它們。

在上一章中,我們看到了方法 map.keys()map.values()map.entries()

這些方法是通用的,有一個共識,就是將它們用於資料結構。如果我們自己建立一個資料結構,我們也應該實作它們。

它們支援

  • Map
  • Set
  • Array

純粹物件也支援類似的函式,但語法有點不同。

Object.keys、values、entries

對於純粹物件,有下列方法可用

請注意區別(例如與 map 相較)

Map 物件
呼叫語法 map.keys() Object.keys(obj),但不是 obj.keys()
傳回 可迭代的 「真正的」陣列

第一個不同點是我們必須呼叫 Object.keys(obj),而不是 obj.keys()

為什麼呢?主要原因是靈活性。請記住,物件是 JavaScript 中所有複雜結構的基礎。因此,我們可能有一個自己的物件,例如 data,它實作自己的 data.values() 方法。我們仍然可以在它上面呼叫 Object.values(data)

第二個不同點是 Object.* 方法傳回「真正的」陣列物件,而不仅仅是可迭代的。這主要是出於歷史原因。

例如

let user = {
  name: "John",
  age: 30
};
  • Object.keys(user) = ["name", "age"]
  • Object.values(user) = ["John", 30]
  • Object.entries(user) = [ ["name","John"], ["age",30] ]

以下是一個使用 Object.values 遍歷屬性值的範例

let user = {
  name: "John",
  age: 30
};

// loop over values
for (let value of Object.values(user)) {
  alert(value); // John, then 30
}
Object.keys/values/entries 忽略符號屬性

就像 for..in 迴圈一樣,這些方法會忽略使用 Symbol(...) 作為鍵的屬性。

這通常很方便。但如果我們也想要符號鍵,那麼有一個獨立的方法 Object.getOwnPropertySymbols,它會傳回一個只有符號鍵的陣列。此外,還有一個方法 Reflect.ownKeys(obj),它會傳回所有鍵。

轉換物件

物件缺少許多陣列中存在的許多方法,例如 mapfilter 等。

如果我們想要套用它們,我們可以使用 Object.entries,然後是 Object.fromEntries

  1. 使用 Object.entries(obj)obj 取得一個鍵/值對陣列。
  2. 對該陣列使用陣列方法,例如 map,來轉換這些鍵/值對。
  3. 對結果陣列使用 Object.fromEntries(array) 將其轉換回物件。

例如,我們有一個包含價格的物件,並希望將它們加倍

let prices = {
  banana: 1,
  orange: 2,
  meat: 4,
};

let doublePrices = Object.fromEntries(
  // convert prices to array, map each key/value pair into another pair
  // and then fromEntries gives back the object
  Object.entries(prices).map(entry => [entry[0], entry[1] * 2])
);

alert(doublePrices.meat); // 8

乍看之下可能很困難,但使用一兩次後就會很容易理解。我們可以用這種方式建立強大的轉換鏈。

任務

重要性:5

有一個包含任意數目薪資的物件 salaries

撰寫函式 sumSalaries(salaries),使用 Object.valuesfor..of 迴圈,回傳所有薪資的總和。

如果 salaries 是空的,則結果必須為 0

例如

let salaries = {
  "John": 100,
  "Pete": 300,
  "Mary": 250
};

alert( sumSalaries(salaries) ); // 650

開啟一個包含測試的沙箱。

function sumSalaries(salaries) {

  let sum = 0;
  for (let salary of Object.values(salaries)) {
    sum += salary;
  }

  return sum; // 650
}

let salaries = {
  "John": 100,
  "Pete": 300,
  "Mary": 250
};

alert( sumSalaries(salaries) ); // 650

或者,我們也可以選擇使用 Object.valuesreduce 來取得總和

// reduce loops over array of salaries,
// adding them up
// and returns the result
function sumSalaries(salaries) {
  return Object.values(salaries).reduce((a, b) => a + b, 0) // 650
}

在沙箱中開啟包含測試的解答。

重要性:5

撰寫函式 count(obj),回傳物件中屬性的數量

let user = {
  name: 'John',
  age: 30
};

alert( count(user) ); // 2

嘗試讓程式碼盡可能簡短。

附註:忽略符號屬性,只計算「一般」屬性。

開啟一個包含測試的沙箱。

function count(obj) {
  return Object.keys(obj).length;
}

在沙箱中開啟包含測試的解答。

教學課程地圖

留言

留言前請先閱讀以下事項…
  • 如果您有改善建議,請 提交 GitHub 議題 或提出 pull request,而非留言。
  • 如果您無法理解文章中的某個部分,請詳細說明。
  • 要插入少量的程式碼,請使用 <code> 標籤,對於多行程式碼,請用 <pre> 標籤包覆,對於超過 10 行的程式碼,請使用沙箱 (plnkrjsbincodepen…)