Photo by Markus Spiske on Unsplash

Setting the Bar ‘Higher’

HIGHER-ORDER FUNCTIONS

Higher-order functions are powerful tools that afford developers the ability to break up a complicated task into smaller, simpler tasks. These small tasks can then work together to tackle the original, more complex problem. Through this technique, code becomes more legible, and bugs become less frequent. To put it plainly, higher-order functions can make developers better at writing code, in more ways than one.

There are many examples of higher-order functions, but there are three that tend to stand out from the others, in terms of both the regularity of which they are used and the various applicable ways in which they can be used. What 3 functions are they? Well, I’m glad you asked; they’re the infamous map, filter, and reduce.

All three of these functions take a callback as one of their arguments, however, reduce can optionally receive another argument, often called a ‘seed’ value. More on that later. They are all called on arrays, and while reduce can return any value, map and filter each return an array. The array returned by map and filter is a brand new array; in other words, the array upon which these higher-order functions are called remains unchanged. In the most basic of terms, these three functions iterate over the collection passed to them and run their passed-in callback function on each item in the collection, before populating a new array with the appropriate values, and returning said array.

How do they actually work?

INTRODUCTION

Map will ultimately populate a new array with the return values of the items in the original array after they are passed through the callback. Filter will run each array element through its callback function and populate a new array with any of the elements that resolve to truthy values. Reduce will, for lack of a better term, reduce the array values into a single value.

MAP

var originalArray = [5, 10, 15, 20, 25];var addFive = function(num){
return num += 5
};
let addFiveArray = originalArray.map(addFive); console.log(addFiveArray); //=> [10, 15, 20, 25, 30]

This demonstrates using the map function on an array of numbers. A function called ‘addFive’ is created, and a variable named ‘addFiveArray’ is initialized to the value of map being called on ‘originalArray’, passing in the ‘addFive’ function. The numbers inside ‘originalArray’ are individually passed into ‘addFive’ and the return values are placed inside a brand new array. This newly created array, with the new values, is then returned. In this example, each number has 5 added to it, before it is placed in the returned array.

var nums = [1, 2, 3, 4, 5];var oddOrEven = nums.map(function(num){
return num % 2 === 0 ? 'even' : 'odd'
});
console.log(oddOrEven); //=> ['odd', 'even', 'odd', 'even', 'odd']

Here, we can see another array named ‘nums’ which is filled with numbers. A variable called ‘oddOrEven’ is initialized to the array calling map. Map has an anonymous callback function passed to it. This callback function checks if the current number has no remainder when divided by 2. If so then the number is even. If the number is even, map will place a string of ‘even’ to the returned array, in the same indexed position as the relevant number in the ‘nums’ array. Finally, an array of strings is returned.

FILTER

var quarterbacks = [
{name: 'Drew Brees', team: 'Saints'},
{name: 'Tom Brady', team: 'Bucs'},
{name: 'Patrick Mahomes', team: 'Chiefs'},
{name: 'Taysom Hill', team: 'Saints'},
{name: 'Josh Allen', team: 'Bills'}
];

var saints = quarterbacks.filter(function(qbObj){
return qbObj.team === 'Saints';
});

console.log(saints); //=> [ {name: 'Drew Brees', team: 'Saints'},
{name: 'Taysom Hill', team: 'Saints'} ]

In this example, we see there is an array named ‘quarterbacks’. The ‘quarterbacks’ array is populated by objects. Each object has a name and a team property. When filter is called with the ‘quarterbacks’ array, an anonymous callback function is passed as the argument of filter, as expected. This example shows one parameter being passed to the anonymous function called ‘qbObj’. This parameter will refer to each object within the ‘quarterbacks’ array. Filter will iterate over them one by one. Then a return statement tells Javascript what it should test each ‘qbObj’ in the ‘quarterbacks’ array for. In this case, Javascript will check whether or not the team property of each ‘qbObj’ is strictly equal to a string of ‘Saints’. If the team property is ‘Saints’, then the function will place the relevant ‘qbObj’ into a new array. After filter has passed all the elements of the ‘quarterbacks’ array through the callback function, it will return an array containing any ‘qbObj’ that has that particular value attached to its team property.

REDUCE

var nums = [1, 2, 3, 4, 5];var sum = nums.reduce(function(acc, curNum){
return acc + curNum;
}, 10);

console.log(sum); // => 25

In the above example, an array of numbers called ‘nums’ is initialized and it is used to call reduce. We can also see that a ‘seed’ of the number 10 is passed into the function. Beginning with 10, each number will be added to the sum of the number that came before it in the array and was previously returned by the callback function. Normally the sum of 1+2+3+4+5 would be 15, but since there is a ‘seed’ of 10, this function will resolve to, and return 25.

var animals = [
{type: 'dog', age: 12},
{type: 'horse', age: 4},
{type: 'dolphin', age: 8},
{type: 'turtle', age: 13},
];

var animalAgeSum = animals.reduce(function(ageSum, curAnimal){
return ageSum + curAnimal.age;
}, 0);

console.log(animalAgeSum); // => 37

Here we see an array of animal objects, each of which has a type and an age property. When using reduce to find the sum of the animal ages, we must include a seed of 0. This is because, if we don't provide a seed, the function will try to add the first item in the array to the value of the age property of the second item in the array. That would not work in this case, as you can’t add an object to a number. As a rule of thumb, look towards the items within the array, specifically their type of value. Then decide what type of value you want to be returned after reduce is finished. If the array items type of value differs from the type of value that is supposed to be returned, then a seed is required. If this is the case, the seed should be the same type of value that should be returned at the end.

CONCLUSION

The Startup

Get smarter at building your thing. Join The Startup’s +751K followers.