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

乍一看可能很困难,但使用一两次后就会很容易理解。我们可以通过这种方式创建强大的转换链。

任务

importance: 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
}

在沙箱中打开包含测试的解决方案。

importance: 5

编写一个函数 count(obj),它返回对象中的属性数量

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

alert( count(user) ); // 2

尝试使代码尽可能短。

P.S. 忽略符号属性,只计算“常规”属性。

打开一个包含测试的沙箱。

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

在沙箱中打开包含测试的解决方案。

教程地图

评论

在评论之前请阅读此内容…
  • 如果你有改进建议,请 提交 GitHub 问题 或提交拉取请求,而不是评论。
  • 如果你无法理解文章中的某些内容,请详细说明。
  • 要插入几行代码,请使用 <code> 标记,对于多行,请用 <pre> 标记将其包装起来,对于超过 10 行的内容,请使用沙箱 (plnkrjsbincodepen…)