使用Object.keys()和Object.values()从对象属性创建数组的区别

5
这里是猫品种的对象,以及每种猫的数量:
const cats = {
  abyssinian: {
    number: 23
  },
  persian: {
    number: 12
  },
  siamese: {
    number: 7
  }
};

假设我想计算所有猫的总数。 我将使用 reduce 来计算数组值的总和。
但是要从上面的对象创建一个数组,我有两个选项:
  1. Object.keys()
  2. Object.values()

// object
const cats = { abyssinian: { number: 23 }, persian: { number: 12 }, siamese: { number: 7 } };

// sum array values with reduce
const total = numbers => numbers.reduce((acc, cur) => acc + cur);

// 1.
// create array with Object.keys()
const numbersByKeys = Object.keys(cats).map(breed => cats[breed].number);
console.log(`Sum with Object.keys(): ${total(numbersByKeys)}`);

// 2.
// create array with Object.values()
const numbersByValues = Object.values(cats).map(breed => breed.number);
console.log(`Sum with Object.values(): ${total(numbersByValues)}`);

什么情况下我会选择其中一个而不是另一个?这里有哪些最佳实践?

还有一个Object.entries方法,它可以获取[key, value]。 - chriss
你最终自己进行了性能分析吗? - Brian Drake
哇,这太老了:P 那时候jsperf还在运行,而另一个评论提到.keys往往更快。但我记得它也取决于浏览器(但这似乎很奇怪?我不知道TBH),所以我会选择感觉更自然的方式。在我的例子中,我根本不需要键(只需要每个猫的数量),所以我会选择.values - Robin Métral
7个回答

10

如果您需要对键执行其他操作而不是检索值,请使用.keys()。否则,如果您可以使用其他方法直接获取值,则仅获取键将是多余的 - 因此,在这种情况下,最好从一开始就使用Object.values()

Object.keys可能有用的示例:

const obj = {
  prop1: 'val1',
  prop2: 'val2'
};

const result = Object.keys(obj).map((key) => [key, obj[key]]);
console.log(result);

您还可以使用 Object.entries 一次获取键和值:

const obj = {
  prop1: 'val1',
  prop2: 'val2'
};

const result = Object.entries(obj).map(([key, val]) => key + '---' + val);
console.log(result);


谢谢你的出色回答!你知道在性能方面有什么区别吗? - Robin Métral
2
Object.keys在处理大型数组时略快一些https://jsperf.com/object-keys-vs-for-in-with-closure/111,但99%的情况下代码清晰度和可读性更为重要。 - Snow
谢谢!我正在处理大对象,所以这可能会有所不同(信不信由你,猫品种对象并不真实)。 - Robin Métral
1
请注意,我在Firefox上运行了测试,发现Object.valuesObject.keys快2倍。但在Chrome上似乎相反。 - Robin Métral

4

Array.from(arrayLike [, mapFn [, thisArg]])还是另一种从类似数组或可迭代对象创建数组的方法,非常简单。第二个参数是一个映射函数,将在数组的每个元素上调用。

 const cats = {
    abyssinian: {
      number: 23
    },
    persian: {
      number: 12
    },
    siamese: {
      number: 7
    }
};
const catsArray = Array.from(Object.values(cats), breed => breed.number)
console.log(catsArray);


如果他们有一个单独的操作将某些内容转换为数组,然后使用 map(),那么使用 Array.from() 结合它们是有意义的。但在这种情况下,他们已经有了一个实际的数组。那么 Array.from() 的意义是什么呢? - Brian Drake

2

由于实际上并未使用键,因此可以使用reduceObject.values和解构来使其更简单和更简洁:

最初的回答。

const cats = {
  abyssinian: {
    number: 23
  },
  persian: {
    number: 12
  },
  siamese: {
    number: 7
  }
};

const totalCats = Object.values(cats).reduce((acc, { number }) => acc + number, 0);

console.log(totalCats);


这有什么优势呢:((acc, { number })((acc, number) 相比? - zer00ne
因为它比(acc, curr) => acc + curr.number更简洁。 - Jack Bashford

0

const object1 = { "11-15" : 115, "16-20" : 68, "21-25" : 4, "26-30" : 0 };

const result = Object.keys(object1).map((key) => {return {name:key, population:object1[key]}});

//[{ name: "11-15", population: 115 }, { name: "16-20", population: 68 }, { name: "21-25", population: 4 }, { name: "26-30", population: 0 }]

console.log(result);


你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community

0
如果性能是一个因素,您可能希望坚持使用Object.keys
这里有另一个人对不同遍历对象的方式进行性能比较的文章。
{{link1:“5种迭代JavaScript对象条目的技术及其性能”}}

谢谢这篇文章!我想知道在 Firefox 上的结果会不会不同,例如(参见此评论)。 - Robin Métral

-1
var total = Object
  .entries(cats)
  .reduce((acc, [name, {number}])=> acc + number , 0);
console.log(total); // 42

-1
const iterableValues = function* (obj) { for (let i of Object.values(obj)) yield i;}
let result = 0;
for (let {number} of iterableValues(cats)) result += number;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接