Iterating over JavaScript objects declaratively or how to map, filter and reduce on objects
Plain javascript objects are very useful, although ES6 provides Map
data structure, it’s still common to use them as key-value structures. But iterating over them its not as easy as using array higher order functions like filter or reduce, what if there exist such functions for js objects too.
Let’s write some of them with the help of Object.entries, folding, spread operator and computed property names (aka dynamic keys).
The idea behind all functions we are going to implement is the same, Object.entries
returns an array of [key, value]
pairs, we iterate over the array and eventualy build up what we want.
map
It takes an object obj
and a functioni fun
and returns a new Object with same keys and fun
applied on all property values. Implementation is pretty simple , we reduce the array retuned by object entries with initial value of {}
and add one property (which is the originial property with fun
applied on it) in each step:
in reducer we flatten the previous object (accumulator) and add the new property.
filter
filter implementation is pretty similar to map but in each step instead of adding the fun
applied property we will check whether predicate satisfies or not and using ternary we will return current property (inside an object) or an empty object and then using spread …
operator we some how flatten ternary result.
reduce
reduce takes three arguments the input object, the reducer function and an initial value.
try to implement fitler and map using implemented reduce function.
Examples
Lets say we have an object of fruits like this:
const fruits = {
apple: {
qty: 300,
color: "green",
name: "apple",
price: 2
},
banana: {
qty: 130,
color: "yellow",
name: "banana",
price: 3
},
orange: {
qty: 120,
color: "orange",
name: "orange",
price: 1.5
},
melon: {
qty: 70,
color: "yellow",
name: "melon",
price: 5
}
};
and want to map them into their colors:
const myFruits = map(fruits, (_, fruit) => fruit.color);
/*
{ apple: 'green',
banana: 'yellow',
orange: 'orange',
melon: 'yellow' }
/*
or filter items with price less than or equal 2:
const myFruits = filter(fruits, (_, fruit) => fruit.price <= 2);
/*
{ apple: { qty: 300, color: 'green', name: 'apple', price: 2 },
orange: { qty: 120, color: 'orange', name: 'orange', price: 1.5 } }
/*
or convert them into an array:
const myFruits = reduce(fruits, (prev, _, fruit) => [...prev, fruit], []);
/*
[ { qty: 300, color: 'green', name: 'apple', price: 2 },
{ qty: 130, color: 'yellow', name: 'banana', price: 3 },
{ qty: 120, color: 'orange', name: 'orange', price: 1.5 },
{ qty: 70, color: 'yellow', name: 'melon', price: 5 } ]
*/
Other functions
Using the idea we used to implement map
, filter
and reduce
you can implement other functions like every
, some
, find
and more.