Well, as last week’s article was such a success (thanks for all the likes and retweets, by the way), I thought I should continue where it left off!
So, last time, we talked about map, filter and reduce, how they work and what they look like behind the scenes.
This time, we will talk about composing those functions, or chaining them together.
Again, we will look at how this looks done with our hand-made functions to get a feel for it, then do it with the “real JS functions.
Short and sweet. Nice. Let’s crack on.
We had an array:
let nums = [1,2,3,4,5,6,7,8,9];
Using our last functions, we will map over it, adding one to each, filter it down to numbers over 5, then reduce what is left down to a total of these values. Expecting a total of 40. I think… (quick maths, u know).
Here goes:
let ourMapResults = map(nums, addOne);
// [2, 3, 4, 5, 6, 7, 8, 9, 10]
let ourFilterResults = filter(ourMapResults, moreThanFive);
// [6, 7, 8, 9, 10]
let ourReduceResults = reduce(0, ourFilterResults);
// 40
Hurrah, and indeed, HUZZAH.
And, as expected, this works fine. It’s fairly simple.
“So, what’s the beef ? you may find yourself asking (you do, right?).
Firstly, you are creating all of these new variables just for the sake of being able to pass them to the next function in the chain. They won’t be used again, they won’t fulfil their life goal as variables. Or something. You wouldn’t want that for your variables, would you?
Also, each item in the chain is doing just one thing. It is easy to keep track of what is going on.
Also, this is a VERY simple example. These chains can go on for a very long time and can get vey complicated. You would have extra variables everywhere, your code base would be (probably) a lot bigger, less maintainable and a lot less clear.
There are probably lots more reasons it is better, but look - it’s a Sunday morning. Stop picking on me!
Anyway - now, let’s do than the “real” way:
let reduceResults = nums.map(addOne)
.filter(n => n > 5)
.reduce((sum, num) => sum + num, 0)
// 40
Something to watch out for in this:
let reduceResults = nums.map(addOne)
.filter(n => n > 5)
.reduce((sum, num) => sum + num, 0)
is the values being used. Firstly, this looks quite strange:
let reduceResults = nums.map(addOne)
addOne doesn’t have anything passed in to it. Really, this is just:
let reduceResults = nums.map(eachNumber => addOne(eachNumber))
map walks through the array and passes each value to the function given (remember, it is just a for loop).
Each function after it is taking the result of the previous one in the chain and bringing it in:
// n = nums.map(addOne)
.filter(n => n > 5)
/*
* It is worth noting here that the name of n can be anything. It is
* generally shortened as much as possible, but this is where it is
* made, you can call it what you want!
*/
.filter(numberOfMagicBeans => numberOfMagicBeans > 5)
Just as an aside, some of you may be familiar with PHP and its dot concatenation (I’m thinking of you here, Bert):
“this . is , “a . “string”
It may help to think of chaining functions to work in a similar way:
"nums.map(addOne)" . "filter(n => n > 5)" . "reduce((sum, num) => sum + num, 0)"
All you are really doing with the dot is accessing the methods stored on the JS array prototype object, over and over again. Remember:
nums.map(addOne)
// nums is an array (array.prototype.map)
thatNewArray.filter(n => n > 5)
// (array.prototype.filter)
newerArray.reduce((sum, num) => sum + num, 0)
// (array.prototype.reduce)
Also, don’t let the ES6 arrow functions confuse you.
They make chains like this easier to read, but watch out for the way they bind to this if you have any OO-ish code.
Really, all we are saying is,
nums.filter(function (number) {
return number > 5;
}
The filter might look a bit tricksy because of all the equals signs and angle brackets (especially if we were checking for >= instead of just >)!
So, there we go. Nice, pretty composed functions.
As before, you can try this in your own terminal – copy and paste, it should work the same way.
If you have any questions, drop me a line.
Maybe there will be more (if I can think of a topic…).
Top comments (0)