Functional Programming in Javascript


Functional programming is new buzz word these which you might be hearing very frequently. I have been myself trying to explore what is functional programming exactly and what it has to do with Javascript. I have come to following conclusions:

  • Functional programming is style of writing code in which you use function as primary data structures.
  • Functional programming involves writing code that does not change state.
  • Functional programming involves writing immutable data structures.
  • Functional programming is not new. It has been there since javascript. It just that no one took javascript too seriously until Angular, React came along.
  • Functional programming is not specific to javascript. It can be done in Python, Scala or clojure. In fact clojure is designed to be “the” functional programming language with built in support for immutable data structures.
  • It is definitely not easy to write functional code if you coming from imperative or object oriented background. But the pain to learn and use it pays off with high quality and testable code.

Why Functional Programming is better?

  • Predictability: Writing code in functional way makes it more predictable. You want to write which you can predict how it will behave.
  • Race Conditions: Functional programming can avoid race conditions by making code stateless and by use of immutable data structures.
  • Testability: Small stateless function makes code concise and are usually easier to test.

 

Non-Functional Example :

var name = "Sam";
var greeting = "Hello";
console.log(greeting+" "+name);//Hello Sam

Functional Example:

function greet (name) {
return "Hello "+name;
}
greet("Sam");//Hello Sam

Imperative vs Object Oriented vs Functional:

Imperative : An imperative style uses a sequence of statements to determine how to reach a certain goal. These statements are said to change the state of the program as each one is executed in turn. Basically your goal is to develop working code as quickly as possible.

In the example below functions are modifying input value. One variable is declared global. Value of global variable is changed from a function. Function capWords could be further break down into smaller functions.

DEMO

var result;

function getText() {
 var someText = prompt("Give me something to capitalize");
 capWords(someText);
 alert(result.join(" "));
};

function capWords(input) {
 var counter;
 var inputArray = input.split(" ");
 var transformed = "";
 result = [];
 for (counter = 0; counter < inputArray.length; counter++) {
 transformed = [
 inputArray[counter].charAt(0).toUpperCase(),
 inputArray[counter].substring(1)
 ].join("");
 result.push(transformed);
 }
};
getText();

Object Oriented:

Object-oriented programming (OOP) is a programming paradigm based on the concept of “objects”, which are data structures that contain data, in the form of fields, often known as attributes; and code, in the form of procedures, often known as methods.

Object-oriented is good when you have a fixed set of operations on things, and as your code evolves, you primarily add new things. This can be accomplished by adding new classes which implement existing methods, and the existing classes are left alone.

DEMO

var SomeText = function(text) {
 this.text = text;
}
SomeText.prototype.capify = function(str) {
 var firstLetter = str.charAt(0);
 var remainder = str.substring(1);
 return [firstLetter.toUpperCase(), remainder].join("");
};
SomeText.prototype.capifyWords = function() {
 var result = [];
 var textArray = this.text.split(" ");
 for (var counter = 0; counter < textArray.length; counter++) {
 result.push(this.capify(textArray[counter]));
 }
 return result.join(" ");
};

var something = prompt("Give me something to capitalize");
var newText = new SomeText(something);
alert(newText.capifyWords());

In the example above, the constructor function simulates a class to model the object. Methods live on the new object’s prototype to keep memory use low. capifyWords is achieved via prototype method. Though this is cleaner than imperative but there are some disadvantages: The methods in the constructor function rely on variables that are scoped to the parent object. There’s a looping construct for iterating across all the members of the array of strings. There’s a countervariable that serves no purpose other than to increment the progress through the for loop. And there are methods that produce the side effect of modifying variables that exist outside of their own definitions. All of this makes the code more brittle, less portable, and makes it harder to test the methods outside of this narrow context.

Functional :

Functional programming is a programming paradigm, a style of building the structure and elements of computer programs, that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data.(This is from wikipedia)

Functional languages are good when you have a fixed set of things, and as your code evolves, you primarily add new operations on existing things. This can be accomplished by adding new functions which compute with existing data types, and the existing functions are left alone.

DEMO

var capify = function(str) {
 return [str.charAt(0).toUpperCase(), str.substring(1)].join("");
};
var processWords = function(fn, str) {
 return str.split(" ").map(fn).join(" ");
};
var something = prompt("Give me something to capitalize");
alert(processWords(capify, something));

Both capify and processWords functions are pure, meaning that they don’t rely on the state of the code they’re called from. The functions don’t create side effects that alter variables outside of themselves. There is one and only one result a function returns for any given set of arguments. Because of these improvements, the new functions are very easy to test, and could be snipped right out of this code and used elsewhere without any modifications.

Map and Reduce:

Map and reduce are two important methods which are more commonly used with functional programming.

Map:

The map() method creates a new array with the results of calling a provided function on every element in this array.map calls a provided callback function once for each element in an array, in order, and constructs a new array from the results. callback is invoked only for indexes of the array which have assigned values, including undefined. It is not called for missing elements of the array (that is, indexes that have never been set, which have been deleted or which have never been assigned a value).

DEMO

var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
alert(roots); //[1, 2, 3]

var numbers = [1, 4, 9];
var doubles = numbers.map(function(num) {
 return num * 2;
});
alert(doubles); //[2, 8, 18]

Reduce:

The reduce() method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.

reduce executes the callback function once for each element present in the array, excluding holes in the array, receiving four arguments:

  • accumulator
  • currentValue
  • currentIndex
  • array

The first time the callback is called, accumulator and currentValue can be one of two values. If initialValue is provided in the call to reduce, then accumulator will be equal to initialValue and currentValue will be equal to the first value in the array. If no initialValue was provided, then accumulator will be equal to the first value in the array and currentValue will be equal to the second.

Example:

DEMO

var sum = [0, 1, 2, 3].reduce(function(a, b) {
 return a + b;
}, 0);
alert(sum);//6

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

Filter:

The filter() method creates a new array with all elements that pass the test implemented by the provided function.filter() calls a provided callback function once for each element in an array, and constructs a new array of all the values for which callback returns a value that coerces to true.

Example:

DEMO

function isBigEnough(value) {
 return value >= 1;
}
var array = [12, 5, 8, 130, 44];
var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
console.log(filtered)// [12, 5, 8, 130, 44]
console.log(array);//[12, 5, 8, 130, 44]
console.log(array===filtered);//false

Note that filtered returns are new array.

Pure Functions:

  1. The function always evaluates the same result value given the same argument value(s). The function result value cannot depend on any hidden information or state that may change while program execution proceeds or between different executions of the program, nor can it depend on any external input from I/O devices (usually—see below).
  2. Evaluation of the result does not cause any semantically observable side effect or output, such as mutation of mutable objects or output to I/O devices (usually—see below).

For example:

DEMO

//Example 1 (Impure function)
var obj = {
 a: 1
};

function calculateValues(items) {
 var b = 1;
//We are modifying here the value of item object (item.a). So this is impure
 items.a = items.a * b + 2; 
 return items.a;
}
console.log(calculateValues(obj)); //3

//Example 2 (Pure)
var obj = {
 a: 1
};

function calculateValuesPure(a) {
 var b = 1;
 a = a * b + 2; //We are not modifying here the value of obj.
 return a;
}

console.log(calculateValuesPure(obj.a)); //3

//Example 3 (Impure)
var obj = {
 a: 1
};
var b = 1; // The output of this function depends on value of b
//(Which is in global scope) and may affect its results. So this impure.

function calculateValues2(a) {
 a = a * b + 2;
 return a;
}

console.log(calculateValues2(obj.a)); //3

//Example 4 (Pure)
var obj = {
 a: 1
};
var b = 1;

function calculateValuesPure2(a, multiplier) { 
//Since the value of b is
// passed as parameter to a function. Now this function only depends upon 
//its parameters. So this pure.
 a = a * multiplier + 2;
 return a;
}

console.log(calculateValuesPure2(obj.a, b)); //3

Immutability:

In object-oriented and functional programming, an immutable object (unchangeable object) is an object whose state cannot be modified after it is created.

var statement = "I am an immutable value";
var otherStr = statement.slice(8, statement.length);//Create a new string
console.log(otherStr)//immutable

Second statements create a new string. And first line statement is not changed at all.The reason is that strings are immutable – they cannot change, we can only ever make new strings.

Mutable Object: 

DEMO

let person = {
 name: 'John',
 age: 28
}
let newPerson = person;
newPerson.age = 30
console.log(newPerson === person) // true
console.log(person) // { name: 'John', age: 30 }
console.log(newPerson) // { name: 'John', age: 30 }

Immutable Object:

let person = {
 name: 'John',
 age: 28
}
let newPerson = Object.assign({}, person, {
 age: 30
})
console.log(newPerson === person) // false
console.log(person) // { name: 'John', age: 28 }
console.log(newPerson) // { name: 'John', age: 30 }

Array Mutable:

let characters = ['Obi-Wan', 'Vader']
let newCharacters = characters
newCharacters.push('Luke')
console.log(characters === newCharacters) // true :-(
console.log(characters); //[ 'Obi-Wan', 'Vader', 'Luke' ]
console.log(newCharacters); //[ 'Obi-Wan', 'Vader', 'Luke' ]

Array Immutable:

let characters = ['Obi-Wan', 'Vader']
let newCharacters = [...characters, 'Luke']
console.log(characters === newCharacters) // false
console.log(characters) // [ 'Obi-Wan', 'Vader' ]
console.log(newCharacters) // [ 'Obi-Wan', 'Vader', 'Luke' ]

Another way to create immutable array using map:

let characters = ['Obi-Wan', 'Vader']
let newCharacters = [];
characters.map(function(character) {
 newCharacters.push(character);
});
newCharacters.push('Luke');
console.log(characters === newCharacters) // false
console.log(characters) // [ 'Obi-Wan', 'Vader' ]
console.log(newCharacters) // [ 'Obi-Wan', 'Vader', 'Luke' ]

Facebook has created a library Immutable.js which provides many Persistent Immutable data structures including: List, Stack, Map, OrderedMap, Set, OrderedSet and Record.

References:

Wikipedia

https://www.sitepoint.com/

https://developer.mozilla.org

https://medium.com/ (Eric Elliott)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s