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