Functional Programming in JavaScript
Unlike in other popular programming languages, functions in JavaScript can be used as variables or parameters in function calls. In short, functions can also be treated as regular values as you would do with strings and numbers. This means that functions can be assigned to variables or passed as arguments to other functions, which are commonly called higher-order functions in functional programming paradigm. To illustrate:
// a simple function
function square(x) {
return x * x;
}
// can also be written as
// an anonymous function passed to a variable, 'square'
var square = function(x)
return x * x;
}
Higher-order functions are just functions that can accept another function as input or return a function as data and they are heavily used in functional programming for organising and reusing code.
This feature in JavaScript is very powerful because it allows you to break down your code into smaller, easier to understand functions and just pass them later as arguments to other functions. Having many smaller functions, instead of one monolithic code block, makes your code simpler to write, easier to read, and more reusable.
Some of the common higher-order functions include – filter
, map
, and reduce
. Let’s try one of the most basic and simple higher-order function, filter
. As the name implies, this higher-order function accepts another function as an argument to filter an array. Let’s see an example to see how it works:
Filtering an Array
// using .filter()
var users = [
{ username: "leatherface", role: "admin", logins: 2 },
{ username: "jigsaw", role: "user", logins: 5 },
{ username: "ashley", role: "moderator", logins: 6 },
{ username: "michael", role: "moderator", logins: 0 },
{ username: "norman", role: "author", logins: 3 },
{ username: "fred", role: "editor", logins: 1 },
{ username: "drsatan", role: "user", logins: 10 }
];
// let's try filtering data using a procedural approach
var filteredUsers1 = [];
for (var i = 0; i < users.length; i++) {
if (users[i].role === "user")
filteredUsers1.push(users[i]);
}
// now, by using the '.filter()' higher-rder function
var filteredUsers2 = users.filter(function(username) {
return username.role === 'user';
});
You will notice that argument passed to filter
function is also a function. This function that is passed as a parameter into another function is referred to as the callback function. What happens is that the filter function iterates over each item, pass each one to the callback function to test whether the current item should be included in the new array, filteredUsers2
. If the callback returns true, the item is added to the new array variable, otherwise, it is ignored. The filter
function simply builds a new array which now contains only the items that passed the test. This is what is termed as a pure function. It does not alter the original array that was passed to it.
Transforming with map
Another very useful higher-order function is map
. Similar to filter
,
it traverses an array and evaluates each of the elements to create a
new array. But instead of discarding some of the items in the array, it
transforms them. The new array generated by using map
contains the same number of items but the each item will be “mapped” to a new form by the function. To demonstrate:
// we'll use the same array in the previous example
var userNames = users.map(function (user) {
return user.username;
});
// userNames array now contains = [ 'leatherface',
// 'jigsaw', 'ashley', 'michael', 'norman', 'fred',
// 'drsatan' ]
The new array now just contains a list of usernames, without the other element properties.
Summarising with reduce
reduce
is commonly used when you want to compute a single value from an array, such as total, minimum, or maximum, etc. You can think of reduce
as folding up an array, one item at a time, passing in the value from the previous call (first argument) and the current item (second argument) to the callback function.
The arguments used by the ‘reduce’ function are the — array, a combining function, and a start value. This method uses the second argument as the starting value
of the callback function. In the example below, it is 0
.
// using reduce
var totalLogins = users.reduce(function(total, user) {
return total + user.logins
}, 0);
Now, let’s try to combine using all three higher order functions to see how they can work together:
var userLogins = users
// filter only users with role 'user'
.filter(function(user) {
return user.role === "user";
})
// return only the login count of the filtered users
.map(function(user) {
return user.logins;
})
// get the total logins of filtered users
.reduce(function(prev, cur) {
return prev + cur
}, 0);
// the total logins for users with role == 'user' is 15
Summary
Since functions in JavaScript are simply values, you can exploit this feature by dividing your code into smaller pieces of functions and combining them them into bigger functions through higher-order functions. Functional programming lets you write better code by making your code broken down into smaller pieces of functions that are easier two write, and understand.