Here's an object of cat breeds, and the number of cats in each:
const cats = {
abyssinian: {
number: 23
},
persian: {
number: 12
},
siamese: {
number: 7
}
};
Suppose I wanted to calculate the total sum of cats. I'll use reduce
to calculate the sum of array values.
But to create an array from the object above, I have two options:
Object.keys()
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)}`);
Here's an object of cat breeds, and the number of cats in each:
const cats = {
abyssinian: {
number: 23
},
persian: {
number: 12
},
siamese: {
number: 7
}
};
Suppose I wanted to calculate the total sum of cats. I'll use reduce
to calculate the sum of array values.
But to create an array from the object above, I have two options:
Object.keys()
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)}`);
When would I choose one over the other? What are the best practices here?
Share Improve this question edited Mar 7, 2019 at 8:01 Jack Bashford 44.1k11 gold badges55 silver badges82 bronze badges asked Mar 3, 2019 at 23:46 Robin MétralRobin Métral 3,2093 gold badges19 silver badges35 bronze badges 3 |7 Answers
Reset to default 10Use .keys()
if you need to do something with the keys other than to retrieve the values. Otherwise, you're only getting the keys in order to access the values, which is redundant if you can get the values directly using a different method - so, in that case, might as well use Object.values()
from the beginning.
An example of where Object.keys
could be useful:
const obj = {
prop1: 'val1',
prop2: 'val2'
};
const result = Object.keys(obj).map((key) => [key, obj[key]]);
console.log(result);
You may also use Object.entries
to get both the key and value at once:
const obj = {
prop1: 'val1',
prop2: 'val2'
};
const result = Object.entries(obj).map(([key, val]) => key + '---' + val);
console.log(result);
Array.from(arrayLike [, mapFn [, thisArg]])
is also another method to create an array from an array-like or iterable object and is really simple. Second argument is a map function to call on every element of the array
const cats = {
abyssinian: {
number: 23
},
persian: {
number: 12
},
siamese: {
number: 7
}
};
const catsArray = Array.from(Object.values(cats), breed => breed.number)
console.log(catsArray);
Since you're not actually using the keys, you can use reduce
with Object.values
and destructuring to make it simpler and more concise:
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);
If performance is a factor, you may want to stick with Object.keys
Here is another person's comparison on the performance of the different ways to iterate over an object.
“5 Techniques to Iterate Over JavaScript Object Entries and their Performance”
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);
var total = Object
.entries(cats)
.reduce((acc, [name, {number}])=> acc + number , 0);
console.log(total); // 42
const iterableValues = function* (obj) { for (let i of Object.values(obj)) yield i;}
let result = 0;
for (let {number} of iterableValues(cats)) result += number;
.keys
tended to be faster. But I remember noticing that it also depended on the browser (but that seems strange? I don't know TBH), so I'd just honestly pick what feels more natural. In my example I don't need the keys at all (just the number of cats in each) so I'd pick.values
– Robin Métral Commented Feb 2, 2022 at 16:33