Functional Programming in Javascript
https://github.com/hari-narasimhan/functional-programming
What's Covered
- Overview
- Pure & Impure Functions
- Higher Order Functions
- Closures
- Currying
- Recursion
- Promises
Overview
Functional programming - is a programming paradigm which treats computation as an evaluation of a mathematical function and avoids changing states and mutating data
It is considered a declarative paradigm since computation is done using expressions instead of statements
Source: Wikipedia
var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Statement
for (var i = 0; i < array.length; i++) {
console.log(array[i]);
}
// Expression
var print = function (p) { return console.log(p); };
array.forEach(print);
Pure & Impure Functions
Pure Functions:
- Return value purely depends on the value of arguments
- No observable side effects during function execution
- Do not mutate the arguments
Impure Functions
- Mutates arguments
- Has Side Effects
// Pure Functions
function square(x) {
return x * x;
}
function squareAll(items) {
return items.map(square);
}
// Impure Functions
function squarePlusOne(x) {
x = x + 1;
// Save x in database :: (side effect)
// updateDb(x);
return x * x;
};
function mutatedSquareAll(items) {
for (var i = 1; i < items.length; i++) {
items[i] = square(items[i]);
}
}
Higher Order Functions
- Functions operating on other functions by either taking them as parameters or returning them are called as higher order functions
- Higher order functions help us abstract over actions not just values
// Return a function
function greaterThan(n) {
return function (m) { return m > n; };
}
var greaterThan10 = greaterThan(10);
console.log(
'9 is greater than 10 ' + greaterThan10(9),
'|',
'11 is greater than 10 ' + greaterThan10(11)
);
// Accept a function
function unless(test, then) {
if (!test) then();
}
function repeat(times, body) {
for (var i = 0; i < times; i++) body(i);
}
repeat(3, function (n) {
unless(n % 2, function () {
console.log(n, 'is even');
});
});
var animals = [
{ species: 'fish', gender: 'male', name: 'Deborah', _id: '576fd6e9cf165226104bd2e2', },
{ species: 'dog', gender: 'female', name: 'Macias', _id: '576fd6e9a268397358d21646', },
{ species: 'frog', gender: 'male', name: 'Mckee', _id: '576fd6e97e6dd7f772b0b718', },
{ species: 'cat', gender: 'male', name: 'Donna', _id: '576fd6e905b46734e87ed252', },
{ species: 'dog', gender: 'male', name: 'Morin', _id: '576fd6e9e049e7c862f29bc5', },
{ species: 'cat', gender: 'male', name: 'Sheena', _id: '576fd6e97c66172ad8df9663', },
{ species: 'dog', gender: 'female', name: 'Stevens', _id: '576fd6e9eeebff173895af6b', },
{ species: 'frog', gender: 'female', name: 'Guy', _id: '576fd6e90b23a8a470030236', },
{ species: 'cat', gender: 'female', name: 'Kane', _id: '576fd6e974e6cbd609e008f6', },
{ species: 'dog', gender: 'male', name: 'Kara', _id: '576fd6e96e41daa122baaa66', },
{ species: 'dog', gender: 'male', name: 'George', _id: '576fd6e9aef91c56c614db05', },
{ species: 'fish', gender: 'female', name: 'Santos', _id: '576fd6e90772c09c45753907', },
{ species: 'frog', gender: 'male', name: 'Vonda', _id: '576fd6e9f28eeb594ef51a07', },
{ species: 'fish', gender: 'female', name: 'Lindsey', _id: '576fd6e9a8b269097f9e3b4c', },
{ species: 'cat', gender: 'male', name: 'Olson', _id: '576fd6e9d19e72ad3981ad64', },
];
// Filter with for loop
var dogs = [];
for (var i = 0; i < animals.length; i++) {
if (animals[i].species === 'dog') {
dogs.push(animals[i]);
}
}
console.log(dogs);
// Using Filter
console.log('using filter');
var isDog = function (a) { return a.species === 'dog'; };
var otherAnimals = function (a) { return a.species !== 'dog'; };
console.log(animals.filter(isDog));
console.log(animals.filter(otherAnimals));
// Let us just print the names
console.log(
animals
.filter(isDog)
.map(function (dog) {return dog.name;}));
var animals = [
{ species: 'fish', gender: 'male', name: 'Deborah', _id: '576fd6e9cf165226104bd2e2', },
{ species: 'dog', gender: 'female', name: 'Macias', _id: '576fd6e9a268397358d21646', },
{ species: 'frog', gender: 'male', name: 'Mckee', _id: '576fd6e97e6dd7f772b0b718', },
{ species: 'cat', gender: 'male', name: 'Donna', _id: '576fd6e905b46734e87ed252', },
{ species: 'dog', gender: 'male', name: 'Morin', _id: '576fd6e9e049e7c862f29bc5', },
{ species: 'cat', gender: 'male', name: 'Sheena', _id: '576fd6e97c66172ad8df9663', },
{ species: 'dog', gender: 'female', name: 'Stevens', _id: '576fd6e9eeebff173895af6b', },
{ species: 'frog', gender: 'female', name: 'Guy', _id: '576fd6e90b23a8a470030236', },
{ species: 'cat', gender: 'female', name: 'Kane', _id: '576fd6e974e6cbd609e008f6', },
{ species: 'dog', gender: 'male', name: 'Kara', _id: '576fd6e96e41daa122baaa66', },
{ species: 'dog', gender: 'male', name: 'George', _id: '576fd6e9aef91c56c614db05', },
{ species: 'fish', gender: 'female', name: 'Santos', _id: '576fd6e90772c09c45753907', },
{ species: 'frog', gender: 'male', name: 'Vonda', _id: '576fd6e9f28eeb594ef51a07', },
{ species: 'fish', gender: 'female', name: 'Lindsey', _id: '576fd6e9a8b269097f9e3b4c', },
{ species: 'cat', gender: 'male', name: 'Olson', _id: '576fd6e9d19e72ad3981ad64', },
];
var summary = animals.reduce(function (acc, animal) {
acc[animal.species] ? acc[animal.species]++ : acc[animal.species] = 1;
return acc;
}, {});
console.log(summary);
Closures
- The ability of a function to remember the environment it was created
- Closures have access to variables which were created in the enclosing scope
-
Use Cases
- Passing data to async callback
var greeting = 'Hello, Spiderman';
var greetMe = function () {
console.log(greeting);
};
greetMe();
function greetingGenerator() {
var name = 'Hello, Superman';
function displayName() {
console.log(name);
}
return displayName;
}
var greeter = greetingGenerator();
greeter();
Currying
- A function which instead of taking all the arguments takes one at a time and returns a function which takes subsequent argument until all arguments are exhausted
function greetInSteps(name, age, location) {
return console.log('Hello ' + name + ' you are ' + age + ' years and from ' + location);
}
greetInSteps('Sam', 21, 'New Delhi');
function curryGreet(name) {
return function (age) {
return function (location) {
return console.log('Hello ' + name + ' you are ' + age + ' years and from ' + location);
};
};
}
curryGreet('Shankar')(25)('Bangalore');
Recursion
- Ability for a function to call itself repeatedly until such a time when it need not call itself (completion)
function reducingCount(n) {
if (n === 0) return;
console.log(n);
reducingCount(--n);
}
reducingCount(20);
Promises
- Promises are similar to callbacks in that they allow us to handle async results.
- Promises are powerful since they can be composed, chained etc.
var Promise = require('bluebird');
var fs = require('fs');
Promise.promisifyAll(fs);
fs.readFileAsync('LICENSE', 'utf-8')
.then(function (data) {
console.log(data);
});
fs.readFileAsync('nofile', 'utf-8')
.then(function (data) {
console.log(data);
},
function (error) {
console.log('Could not read "nofile"', error);
});
Functional Programming in Javascript
By Hari Narasimhan
Functional Programming in Javascript
A short course on functional programming in Javascript
- 1,211