ES6 can be short and precise. Look at this tiny algorithm that I use quite regularly. It converts a list of objects to a lookup table / index / object that can be access the entries more effiently for repetitve lookup tasks.
The goal I have a list of objects (mediaList
) and want to create a look up table from it by one of it's properties (id
), assuming that this property is unique.
Input
const mediaList = [
{ duration: 514, id: 'vO4vti9JJ2Q', type: 'youtube' },
{ duration: 3531, id: 'ozD4h9HCHOY', type: 'youtube' },
]
Output
const lookupTable = {
vO4vti9JJ2Q: { duration: 514, id: 'vO4vti9JJ2Q', type: 'youtube' },
ozD4h9HCHOY: { duration: 3531, id: 'ozD4h9HCHOY', type: 'youtube' },
}
The old way
This is the code I used to write in ES5.
var lookupTable = {};
for (var i = 0; i < mediaList.length; i++) {
lookupTable[id] = mediaList[i].id
}
I never thought about changeing this approach until I discovered Death of the For Loop and similar articles. The arguments for a functional coding style are quite complelling for this problem. It decreases the characters you have write and the cognitive load when reading code, by decreasing the number of items that your mind has to track. To achieve this you need to get familiar with the ES6 syntax, now available in modern browsers or through polyfills.
The new way
The look up table in ES6 code
const lookupTable = mediaList.reduce(
(acc, media) => ({ ...acc, { [media.id]: media } })
, {})
The Disection
Starting with the inital for
loop
var lookupTable = {};
for (var i = 0; i < mediaList.length; i++) {
lookupTable[id] = mediaList[i]
}
The ES6 code can be construted part by part by replacing it with ES6 syntax.
Step 1,
replacing the for
loop with an array .reduce()
function.
const lookupTable = mediaList.reduce(
function(acc, media) {
const newItem = {};
newItem[media.id] = media;
return Object.assign( acc, newItem);
},
{} // initial value of `acc`, the accumulator object
)
Step 2,
the object {}
creation is replaced with the sorter object literal syntax { [attrName]: val }
const lookupTable = mediaList.reduce(
function(acc, media) {
return Object.assign( acc, { [media.id]: media });
},
{}
)
Step 3,
the function
call with the shorter =>
arrow function
const lookupTable = mediaList.reduce(
(acc, media) => Object.assign( acc, { [media.id]: media }),
{}
)
Step 4,
and the Object.assign
with the sorter ...
object destructuring
const lookupTable = mediaList.reduce(
(acc, media) => ({ ...acc, { [media.id]: media } })
, {})
Alternative with smaller transpile footprint
Since the spread operator takes up a lot of transpiled code I use another variant of this pattern.
const lookupTable = mediaList.reduce(
(acc, media) => Object.assign(acc, { [media.id]: media }),
{}
)
But if you read this, most likely in a couple of years from when I wrote this, you will not need to transpile the code anymore and you can savely ignore this paragraph.
Conclusion
Admittedly it is hard to see with this example alone, but my experinece showed me that functional ES6 code
- deceased my code length, and
- lowerd my error rate.
The End