Introduction to functional JavaScript | Perpetuum Mobile

Introduction to functional JavaScript

Zvonimir Dimovski JavaScript

Functional programming approach was popular in 70's and 80's last century in academic world. During 90's and beginning of the new millennium it was a bit left aside with rise of imperative (object oriented) approach that took place with languages like Java and C++.

It is hard to find exact definition of the approach, however people tend to describe functional programming as pure math (see lambda calculus) and that was the main reason why broader programming community did not adopt it.

However, with recent renaissance of large distributed systems the need for functional programming has exploded. I will not go into the deep with explanations and examples which is irrelevant for this blog post, I will just mention the fact that programs written with functional approach are using resources better than their counterparts.

Learn and lead

Concepts

Main concepts in functional programming are: Immutability and Statelessness.

First concept "Immutability" means that data should be immutable. Scary word, however it is easy to grasp and means that data after it is created should never change. In JavaScript strings and numbers are immutable by the design.


var myStr = "ABCDE";  
myStr[2] = 'C'; // trying to change letter "C" to "Z"  
console.log(myStr) // ABCDE 

Variable myStr will remain the same. The only way is to do string manipulation is to use methods such as trim() or slice() that will return a new strings.

The story is different with arrays. The list of array methods that modify array (or don't) can be found here

Take a look at this simple example with arrays:


var array1 = ["Cat", "Bird", "Elephant"];  
var array2 = array1.push("Dog");  
console.log(array2); // 4 (length of an array1)  
console.log(array1); // Cat, Bird, Elephant, Dog 

People would think that array2 will contain all strings from array1 plus new string Dog. In JavaScript it is not the case. array2 now contains only the new length of array1. From this case we can also see that push() is mutable method on array.

Second concept "Stateless" means that called function with same arguments always returns same result and it will not change current program's enviroment. Here is a simple example:


var num = 2;  
var square = function(n) {  
    return n * n;  
};  
square(num); // 4 

After executing square function variable num will stay the same and function square will return the same value for same given argument.

Why?

In the past JavaScript was used to handle simpler tasks on the web page. It usually was simple DOM manipulation. Recently with rise of JavaScript frameworks like Angular or React for building complex rich user interfaces functional programming came to the spotlight. Breaking application into smaller simpler reusable parts speeds application development process and make it more error/bug resistant. Not to mention that programmers that inherit code written this way will be happy, because complexity confuses programmers :)

Higher order functions

One of characteristics of JavaScript that makes it good for functional programming are higher order functions. Text book definition is: Functions that operate on other functions, either by taking them as arguments or by returning them, are called higher-order functions. Actually, in JavaScript functions are values what we can see from bellow example


var square = function(n) {  
    return n * n;  
}  
var somethingElse = square;  
somethingElse(20); // 400 

In this case we assigned anonymous function to the variable square and we can pass it on to another variable (in our case somethingElse). This is important fact where you can compose your program of the smaller pieces into a bigger picture.

Lets look at few built-in higher order functions in action. In this tutorial I will mention three most used higher order functions operating upon arrays that return a new array: map and filter (others are not covered buy this blog post). I will also make a comparison of code complexity with traditional approach vs. functional concept.

map()

Map() is a function that returns a new array (it is not modifying existing array - remember Immutability) with result of calling a function for every array element. Lets create simple array of numbers and create a function that returns an array of square root numbers.


// Traditional "no-no" approach   

var numbers = [1, 4, 9];

var squareRoot = function() {
    var newNumbers = [];
    for(var i = 0; i < numbers.length; i++) {
        newNumbers.push(Math.sqrt(numbers[i]));
    }

return newNumbers;
}     
squareRoot() // [1, 2, 3]

Lets write the same thing with functional approach


// Functional approach  

var numbers = [1, 4, 9];  

var squareRoot = function() {  
    return numbers.map(Math.sqrt);  
}

squareRoot() // [1, 2, 3] 

Woooot??? In traditional way we needed 8 lines of code, but in functional we just needed 4 lines of code to get the same result. This is small scale and simple example, but imagine application of few thousands of lines of code that could be reduced by half. If we go deeper with analysis and count number of characters in two approaches in traditional way we wrote 194 characters, but in functional we wrote 89 characters. Reduction is obvious.

Now, maybe you thought this is maximum reduction that you can get. You are wrong :) Lets use ECMAscript 2015 (or ES6) syntax to get things in interstellar space.


// Functional approach with ES6  

var numbers = [1, 4, 9];

var squareRoot = () => numbers.map(Math.sqrt);  

squareRoot() // [1, 2, 3]

With ES6 we created one-liner function with even smaller number a character (72) used to write a function.

filter()

Filter() is a function that returns a new array that contains all array elements that pass the test implemented by the provided function.

In this example we want to extract people with same last name. We created an array of 5 objects called people that we want use as template for given function.


// Traditional way

var people = [  
    {firstName: "John", lastName: "Doe"},  
    {firstName: "Mary", lastName: "Lynch"},  
    {firstName: "Ann", lastName: "Smith"},  
    {firstName: "Silvester", lastName: "Stallone"},  
    {firstName: "David", lastName: "Smith"},  
];  

var sameLastName = function() {  
    var smiths = [];  
    for(var i = 0; i < people.length; i++) {  
        if(people[i].lastName === 'Smith') {  
            smiths.push(people[i]);  
        }
    }
    return smiths;  
}  

sameLastName() // array of 2 objects containing Ann Smith & David Smith

I really wanted to filter out Silvester Stallone, but he is one of a kind. However, people with same last name are Ann Smith and David Smith. There is nothing wrong with this example above, except that we want it to create it more programmer friendly and fortunately we have solution using filter() method.


// Functional way  

var people = [  
    {firstName: "John", lastName: "Doe"},  
    {firstName: "Mary", lastName: "Lynch"},  
    {firstName: "Ann", lastName: "Smith"},  
    {firstName: "Silvester", lastName: "Stallone"},  
    {firstName: "David", lastName: "Smith"},  
];  
var sameLastName = people.filter(function(person) {  
    return person.lastName === 'Smith'  
})  

sameLastName // array of 2 objects containing Ann Smith & David Smith 

Again, the reduction is huge, but we want to make it even more optimized with ES6.


// Functional way with ES6 

var people = [  
    {firstName: "John", lastName: "Doe"},  
    {firstName: "Mary", lastName: "Lynch"},  
    {firstName: "Ann", lastName: "Smith"},  
    {firstName: "Silvester", lastName: "Stallone"},  
    {firstName: "David", lastName: "Smith"},  
];  
 
var sameLastName = people.filter( (person) => person.lastName === 'Smith' )  

sameLastName // array of 2 objects containing Ann Smith & David Smith  

Conclusion

In these few examples I tried to show beauty and efficiency of functional approach. There are other concepts that are also not covered like Monads which are important part of functional programming. I leave Monads as separate theme that will be covered in one of my next blog post, because of complexity of the subject.

If you are starting with JavaScript or you are casual developer this will be good starting point to establish proper mindset that you need to have if you are going to start building apps with ReactJS which is leaning towards functional programming approach.