Composability in JavaScript

Consider how we would have written the previous example (finding the biggest script) without higher-order functions. The code is not that much worse.

let biggest = null;

for (let script of SCRIPTS) {

if (biggest == null ||

characterCount(biggest) < characterCount(script)) {

biggest = script;

}

}

console.log(biggest);

// → {name: “Han”, …}

There are a few more bindings, and the program is four lines longer.

But it is still very readable.

Higher-order functions start to shine when you need to compose opera­tions. As an example, let’s write code that finds the average year of origin for living and dead scripts in the data set.

function average(array) {

return array.reduce((a, b) => a + b) / array.length;

}

console.log(Math.round(average(

SCRIPTS.filter(s => s.living).map(s => s.year))));

// → 1188

console.log(Math.round(average(

SCRIPTS.filter(s => !s.living).map(s => s.year))));

// → 188

So the dead scripts in Unicode are, on average, older than the living ones. This is not a terribly meaningful or surprising statistic. But I hope you’ll agree that the code used to compute it isn’t hard to read. You can see it as a pipeline: we start with all scripts, filter out the living (or dead) ones, take the years from those, average them, and round the result.

You could definitely also write this computation as one big loop.

let total = 0, count = 0;

for (let script of SCRIPTS) {

if (script.living) {

total += script.year;

count += 1;

}

}

console.log(Math.round(total / count));

// → 1188

But it is harder to see what was being computed and how. And because intermediate results aren’t represented as coherent values, it’d be a lot more work to extract something like average into a separate function.

In terms of what the computer is actually doing, these two approaches are also quite different. The first will build up new arrays when running filter and map, whereas the second computes only some numbers, doing less work. You can usually afford the readable approach, but if you’re processing huge arrays, and doing so many times, the less abstract style might be worth the extra speed.

Source: Haverbeke Marijn (2018), Eloquent JavaScript: A Modern Introduction to Programming,

No Starch Press; 3rd edition.

Leave a Reply

Your email address will not be published. Required fields are marked *