Functional Programming Using JavaScript

Programmers use different techniques to achieve abstraction and hide complexity e.g Object Oriented techniques does exactly that. They do so because programs grow at fast pace and they quickly become complex. Humans are intelligent but they can handle complexity to a particular level. So basically Functional programming is also used to hide complexity of programs using functions.

What is Functional Programming?

Functional programming, produces abstraction through clever ways of combining functions. ‐ Eloquent JavaScript

Here the word “functions” is important because you will be hiding complexity using functions. Now I will explain some important functional programming concepts. First you need to understand what’s Function Application?


Function Application

In some pure functional languages, there’s no concept of function call. We actually apply a function to data instead of calling it. In JavaScript you can actually both call or apply a function. Let me give an example of that.

1
2
3
4
5
6
7
8
9
10
11
12
13
function sum(a, b) {
    var c = a + b;
    console.log('Sum: ' + c);
}
 
//function call
sum(2, 3);
 
//function application
sum.apply(window, [2, 3]);
 
//passing null is same as passing window
sum.apply(null, [2, 3]);

In above example, a sum function is defined which adds two numbers. To call this function, we write the name of function, then paranthesis, and pass parameters to it.

Now this function can be applied to dataset and will have same result as function call. That’s done on line 10. apply method takes two parameters. First is the object to which you want to bind sum function. Binding means the keyword this will point to window object within sum function. Second parameter of apply method is an array containing the set of parameters which will be passed to sum function.

Function application on line 10 can also be written as on line 13. Whenever we want to bind the function to global object i.e. window object, we can pass null as the first parameter.

Let’s take a look at another example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var obj = {
    data: 'this is some data...',
 
    myFunc: function () {
        console.log(this.data);
    }
};
 
//placing obj.myFunc to global namespace
var myFunc = obj.myFunc;
 
//function call
obj.myFunc();
 
//function application
myFunc.apply(obj);

An object is defined using object literal and then a property data is defined and a string is assigned to it. Then a function myFunc is defined which prints the property this.data to console.

To call myFunc method we can write obj.myFunc(). But to apply this function we need to write myFunc.apply(obj). obj object is passed to apply because we want to bind myFunc to obj which means the keyword this will point to obj when myFunc executes. Note that we don’t pass the parameter array because this function doesn’t require any parameter.


Higher-Order Functions

Second important concept that you need understand is Higher-order function.

A function that accept functions as argument or returns a function as output. ‐ Wikipedia

Let’s take a look at an example.

function GetSumFunc(a) {
    return function (b) {
        return a + b;
    };
}
 
var sum = GetSumFunc(3);
console.log(sum(2));

Here GetSumFunc is a higher-order function because it returns another function which accepts b as parameter and returns the sum of parameters a and b. This example looks simple but it uses two (other than higher-order function) important JavaScript concepts.

Closure

It uses closure to maintain state. You maybe thinking what state it’s maintaining? It’s actually maintaining the value of parameter a for inner function which is returned. When we called GetSumFunc with 3 as its parameter, it returns a new function. Now this new function has access to the value of parameter a even after the execution of GetSumFunc completes. So this is how it’s maintaining state of parameter a.

Initially it looks odd to programmers coming from other languages but to be honest it’s one of the most useful feature of JavaScript and it’s called closure and this exactly what closure is. i.e. returned function having access to state of its higher order function even after the execution of high-order function completes.

Partial Function Application

Now the second concept used in the above example is the Partial Function Application. We know that calling a function is actually applying it to set of parameters or data (Function Application). Partial Function Application is applying a function to partial data, not on the complete dataset. Partial Function Application is used when partial set of data is known and it’s confirm that this partial data will remain same among different function calls. So instead of repeatedly passing that same partial known data, we partially apply the function to that dataset.

In the above example we always want to add 3 with some unknown number. So we know our partial dataset in advance so instead of creating a function which accept two parameters, we make use of partial function application. We made a function which know its first parameter in advance i.e. the higher order function. Second parameter is passed to the inner function which is unknown.


forEach

So far we have discussed two important concepts related to functional programming. First is Function Application, second is Higher Order Functions. Now using these concepts, we will be doing some functional programming in JavaScript.

Let’s say you have an array of numbers. How would you print them? Of course we will use for loop and iterate over the array and i variable which will be used to access current element.

var arr = [3, 5, 2, 6], i;
 
for (i = 0; arr[i]; i += 1) {
    console.log(arr[i]);
}

If you look carefully at the code, there’s lot of things going on in this loop. First i is initialized to zero, then loop’s condition is checked, then the body executes, then it iterates the variable, then it checks the condition again, if it’s true then execute the body again. So what I mean here’s that instead of focusing on the logic in the body of the loop, you also need to focus on the loop mechanics.

When we write complex algorithms, such kind of loops add complexity to our programs. Can we hide the loop mechanics? The answer to this question is functional programming. To hide complexity we will make use of functions.

In ES5, forEach method was introduced which can be used to iterate over arrays. Let’s rewrite above loop in functional way.

var arr = [2, 5, 3, 6];
arr.forEach();

First an array of numbers arr is defined. Then to iterate over this array, we need to write only arr.forEach(). Now your only focus will be on the logic which you want to apply on each element in an array. In our case that logic is to print current element of an array. Let’s write a function that do that.

function printElm(d) {
    console.log(d);
}

To apply this function on each element in an array arr, we pass it to forEach. Here’s the final code that prints each element in an array in functional way.

var arr = [2, 5, 3, 6];
 
function printElm(d) {
    console.log(d);
}
 
arr.forEach(printElm);

As you can see function printElm is passed to forEach method. If you are still wondering what’s the benefit of iterating over an array using a function? We removed the loop mechanics and only focused on the functionality that we want to perform on each element in the array i.e. we only focused on body part of the loop. So this is how we achieved abstraction using a function forEach. Also note that forEach is a higher-order function because it takes printElm function as parameter.

The parameters that forEach passes to printElm will be the current element (in our example it’s d). Second parameter is the index of current element. Finally the third parameter is the original arr on which we are iterating. But for our case, we don’t need current index and original arr. So we omitted them from the parameter list and worked only with d.

Let’s take a look at another example that does a shallow copy of an object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function shallowCopy(o) {
    var propNames = Object.getOwnPropertyNames(o);
    var c = {};
 
    //copy operation...
    propNames.forEach(function (n) {
        c[n] = o[n];
    });
 
    return c;
}
 
//to test shallowCopy, obj is created
var obj = {
    name: 'Fawad',
    email: 'fawad@ifadey.com',
    web: 'www.ifadey.com'
};
 
//call shallowCopy with obj passed to it
//it will return copy of obj and prints on console
console.log(shallowCopy(obj));

shallowCopy function accepts one parameter i.e the object o and returns the shallow copy of o. One line 2, variable propNames is assigned list of own property names of an object which we want to copy. We get the list using getOwnPropertyNames() method and it was introduced in ES5.

Note: Alternate way to iterate over property names is using for in loop.

On line 3, object c is created which will be the shallow copy of object o.

Line 6 has the copy operation done using forEach method. Within the forEach method, anonymous function is passed which will get executed for each element in propNames. This anonymous function takes n as argument which is basically the current element being iterated. With the anonymous function, current property in n is copied from object o to c.

Finally on line 10, object c is returned.

Look at the conciseness and beauty of the code when written in functional way. To test this function an object obj is created and assign some properties to it. Now call shallowCopy function and pass obj object to it. Finally log the output of shallowCopy to console.



reduce

Let’s say you want to add all the numbers in an array. The obvious solution is to use forEach method to loop over an array and add each element.

function sumArr(arr) {
    var sum = 0;
 
    arr.forEach(function (d) {
        sum += d;
    });
 
    return sum;
}
 
console.log(sumArr([2, 5, 9, 1]));

But there’s a better solution to this using reduce function. reduce function reduces the list of items to one. Now we can apply reduce method to our sum example because we are reducing the list of array elements to one by summing them. Let’s rewrite our sum example using reduce function.

function sumArr(arr) {
    return arr.reduce(function (pre, cur, i, arr) {
        return pre + cur;
    }, 0);
}
 
console.log(sumArr([2, 5, 9, 1]));

reduce is applied to each element on arr. reduce method takes two parameters. First is the function where our logic will go. Second is the start or init value. In our case we passed 0 (zero) as init value and first parameter is anonymous function which takes four parameters.

  1. pre is the previous value so far calculated and returned from anonymous function. On the first run, it will be the init value (zero) that we passed to reduce as 2nd parameter.
  2. cur is current value in arr being iterated.
  3. i is the current index.
  4. arr is original array being iterated.

i and arr parameters are not required in our example so you can safely omit them. Within the anonymous function, sum of pre and cur are returned. This returned value is passed to pre parameter on next iteration.

Here’s another example taken from Mozilla Developer Network. It flattens the list the two dimensional array to one dimensional.

var arr = [[0, 1], [2, 3], [4, 5]];
 
var flattened = arr.reduce(function (a, b) {
    return a.concat(b);
}, []);
 
console.log(flattened);

Here we passed blank array [] as init value and on each iteration, a will contain the array so far concatenated and b will contain the current array in arr (as each item in arr is also an array).

One final example which reduces list of words to single sentence.

function getSentence(words) {
    var sentence = words.reduce(function (p, c) {
        return p + ' ' + c;
    }, '');
 
    return sentence;
}
 
var s = getSentence(['Wao!', 'reduce()', 'function', 'is', 'super', 'awesome!']);
console.log(s);

Nothing special here. Again done using the same concepts explain above.

Note: Above code is for demonstration purpose. In real code, you can easily concatenate all words in an array using join function like so: ['These', 'are', 'the', 'words.'].join(' ')

Note: Don’t forget to check reduceRight function which also reduce list of items to one but it start reducing the list from right-to-left.

map

Let’s say you want to round all numbers in an array. One solution could be using forEach function.

var arr = [];
 
[2.5, 5.6, 1.2].forEach(function (d, i) {
    arr[i] = Math.round(d);
});
 
//[3, 6, 1]
console.log(arr);

Simply iterating over array containing floating point numbers and overwriting each element with a rounded one. We can rewrite above example more concisely and in a better way using map function. map function, as its name states, maps or transforms each item in the list and returns the new list containing those mapped items. Now this is exactly what we want to do in our previous example.

var arr = [2.5, 5.6, 1.2].map(function (d) {
    return Math.round(d);
});
 
console.log(arr);

map is applied to hard coded array and on each iteration, current element is passed to function that’s passed to map. This anonymous function simply rounds the number and returns it which gets added in the new array which in the end is returned by map.

Here’s another example. Let’s say you want to convert the NodeList of menu items to an array of textContent.

Note: textContent is of type string and it contains text (ignoring HTML tags) inside the element.

var menuItems = document.querySelectorAll('#menu > li');
 
//convert NodeList to Array of DOM Elements
menuItems = Array.prototype.slice.call(menuItems);
 
//map DOM Elements Array to textContent Array
menuItems = menuItems.map(function (d) {
    return d.textContent;
});
 
//["item 1", "item 2", "item 3"]
console.log(menuItems);

document.querySelectorAll returns a list of type NodeList. NodeList don’t have these functional methods explained so far. But we can easily convert other type of lists to arrays using Array.prototype.slice.call(list). So on line 4, we converted NodeList to Array and assigned it to menuItems.

On line 6, map is applied to menuItems and within the anonymous function passed to map, each element’s textContent property is returned. After iterating over all elements, new array containing mapped elements is returned from map and assigned to menuItems again.


filter

filter function iterates over a list and returns a new list containing elements for whom the passed function returns true. For example you want to get all elements whose innerHTML is empty.

var allNodes = Array.prototype.slice.call(document.querySelectorAll('body *'));
 
var empNodes = allNodes.filter(function (elm) {
    return elm.innerHTML === '';
});
 
console.log(empNodes);

On line 1, we converted NodeList to Array and assigned it to allNodes.

filter function will add only those elements to new array who fulfil the condition on line 4 (elm.innerHTML === ''). Array containing elements having empty innerHTML is assigned to empNodes.

Let’s take a look at another example in which we will implement our own getElementsByClassName function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function getElementsByClassName(nList, className) {
    var elms = Array.prototype.slice.call(nList);
 
    return elms.filter(function(d) {
        var found = false;
 
        d.className
         .split(' ')
         .forEach(function (d) {
             if (d === className) {
                 found = true;
             }
         });
 
        return found;
    });
}
 
//returns all the elements having class 'title'
var classTitleElms = getElementsByClassName(
    document.getElementsByTagName('*'),
    'title'
);

getElementsByClassName takes two arguments. First is the NodeList of elements (nList) in which we want to search className which is the 2nd parameter.

On line 2, nList of type NodeList is converted to an array so we can use filter method on it.

On line 4, filter method is applied to elms and passed anonymous function that will check whether the className exist in current element being iterated.

Note: In JavaScript you can access class name(s) of elements using htmlElement.className property. If multiple class names are added to the element, this property will contain all of them separated by space character.

On line 7, all class names applied to current element d were split on the basis of space character. Then forEach is applied to the list of class names returned from split method.

Existence of className is checked on line 9. found is set to true if it exist.

found is returned from the anonymous function for filter. filter function add those elements for which passed function returns true.

Finally list of filtered/matched elements is returned from filter which we directly returned out of getElementsByClassName function using return keyword (line 4).


every

every function returns true only if all the elements are validated by the function passed to every. Let’s say you have an array of identifier names so you want to make sure none of them contains space character.

var validIds = ['str', 'idx', 'someObj'],
    someInvalidIds = ['abc', 'hello world', 'tst'];
 
function validateId(id) {
    //make sure no space exist in id
    return id.indexOf(' ') === -1;
}
 
//returns true
console.log( validIds.every(validateId) );
 
//returns false
console.log( someInvalidIds.every(validateId) );

every returned false for someInvalidIds because one identifier 'hello world' was not validated by passed function validateId.


some

some function returns true if at least one element is validated by the function passed to some. Let’s rewrite getElementsByClassName example using some instead of forEach.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function getElementsByClassName(nList, className) {
    var elms = Array.prototype.slice.call(nList);
 
    return elms.filter(function(d) {
 
        return d.className
                .split(' ')
                .some(function (d) {
                    return d === className;
                });
 
    });
}
 
//returns all the elements having class 'title'
var classTitleElms = getElementsByClassName(
    document.getElementsByTagName('*'),
    'title'
);

As you can see the use of some has further decreased the code and looks much prettier. some in above example will return true if it founds the className in class name list (d.className) of current element being iterated by filter function.


Summary

You have learned about functional programming and concepts related to it like Higher-Order Functions, Function Application. Then we have seen functional methods forEach, map, reduce, filter, some, every. If you look close at the working of these functions, you will note that all of them are based on basic concepts that were explained at the start of this article.

Remember that these are not only the functions that have functional nature. There are other functions in JavaScript like sort which allow you to write code in functional way. Plus you can write your own Higher-order functions to implement this functional style of programming.

All of these functions are excellent tools to write concise, clean, and maintainable code which hide lots of complexity if implemented without them. Other benefit of using them is you focus on the core logic instead thinking about the supporting logic that helps the core logic to execute. These functions can also be used in combination to solve more complex problems. In short we achieved simplicity, and abstraction in our code using functions in clever ways.

All the functions (forEach, map, reduce, filter, etc) that are explained here are part of ES5. You can easily implement them in pre ES5 environment but you can also use libraries like Underscore.js which implement all of these functions and much more.


comments powered by Disqus