Functional Programming in JavaScript

| Comments

The Mastering the Arcane Art of JavaScript-mancy series are my humble attempt at bringing my love for JavaScript to all other C# developers that haven’t yet discovered how awesome this language and its whole ecosystem are. These articles are excerpts of the super duper awesome JavaScript-Mancy book a compendium of all things JavaScript for C# developers.

Functions are one of the most foundational and common constructs in JavaScript. We use them for all kinds of things: to abstract, encapsulate and reuse functionality, as object factories and constructors, to simulate data privacy, to create namespaces and modules, we can compose them with other functions… They are everywhere.

The fact that functions are so prevalent in JavaScript, that they are first-class citizens and that it is very natural to use higher-order functions, makes JavaScript a great language to do functional style programming.

But what does all this nonsense of first class citizenship and higher-order functions means? Why should you care about functional programming in the first place? And moreover… What the heck is functional programming?

What is Functional Programming?

Functional programming is a paradigm where programs are written by building, composing and evaluating functions as if they were mathematical functions. Special functions which are often characterized by the avoidance of changing state, side-effects and using immutable data.

Why Should You Care About Functional Programming?

The application of functional programming results in a very declarative style of coding where you encapsulate every bit on computation in reusable functions and then combine them together to build greater abstractions and achieve more complex tasks. As such, functional programming style code is very concise and easy to read.

Because functional programming encourages the use of pure functions, deterministic functions with no side-effects whose outputs are totally determined by their inputs, programs written following these principles are very testable and less bug prone. Additionally, following the logic and predicting the behavior of your program becomes much easier.

Functional programming also excels at turning implicit requirements or code contracts into explicit programmatic requirements which help clarify the intention of your code and makes it more readable and easier to understand. In fact, one could say that functional programming is the art of turning the implicit into something explicit.

In summary, functional programming helps you:

  • Write reusable code
  • Write concise, readable code
  • Write less bug prone code that is easier to test
  • Make your program behavior easier to understand and predict
  • Make your code more intentional by turning implicit requirements into explicit ones

Sounds interesting? Then let’s get started in the path of the functional programeer.

In the next few sections we will go through different functional programming concepts that are often thrown around willy-nilly when talking about functional programming and which you may not be very comfortable or familiar with. So we will help you become more comfortable in this new terrain and explain concepts like pure functions, higher-order functions, closures, etc… using simple examples so you can get a good foundation and gain enough confidence to start writing functional flavored code right away.

Functions As First Class Citizens

You can experiment with all examples in this article directly within this jsBin or downloading the source code from GitHub.

A language is said to have first-class functions or functions as fist class citizens when functions behave like any normal value within the language, that is:

  • you can store them in a variable
  • you can pass them as an argument to other functions
  • you can return them from other functions

This means that functions are not a special mystical construct that can only be defined within the context of a class, but a fundamental construct in their own right that can be used anywhere within a program.

JavaScript is a language that has first class functions. In JavaScript, you can store a function in a variable:

1
2
3
const add = (a, b) => a + b;
console.log(`1 + 2 = ${add(1, 2)}`);
// => 1 + 2 = 3

You can pass it as an argument to another function:

1
2
3
4
const magicNumbers = [1, 2, 3, 4];
const sum = magicNumbers.reduce(add);
console.log(`${magicNumbers.join(' + ')} = ${sum}`);
// => 1 + 2 + 3 + 4 = 10

Where the 1 reduce function performs the addition (via add) of each item within the array.

And finally you can return a function from another function:

1
2
3
4
const addX = x => b => add(x, b);
const add10 = addX(10);
console.log(`100 + 10 = ${add10(100)}`);
// => 100 + 10 = 110

In this example, we create a more specific addition function where we fix one of the arguments. The addX function effectively works as a factory for other functions.

Arrow functions used in this fashion can be a little bit daunting or hard to compute when you are not familiar with functional programming. But if we expand them to look like classical anonymous function expressions you’ll be able to appreciate the returning function more clearly:

1
2
3
4
5
6
7
const addXX = function(x) {
  return function(b) {
    return add(x, b);
  }
}
console.log(`100 + 10 = ${addXX(100)(10)}`);
// => 100 + 10 = 110

Functions as first class citizens are a necessity for functional programming because they are a fundamental piece in being able to define higher-order functions.

What are Higher-order Functions?

A Higher-order function (also known as functional form or functor) is a function that has at least one of the following characteristics:

  • It takes one or several functions as an argument
  • It returns a function

All the other functions that you are familiar with are what we know as first-order functions.

You’ve already seen higher-order functions in action in the previous section. For instance, the Array.prototype.reduce function is a higher-order function because it takes a function as an argument. A naive implementation of reduce could look like this:

1
2
3
4
5
6
const reduce = (array, reducingFunction, initialValue = 0) => {
  let result = initialValue;
  for (let item of array)
    result = reducingFunction(result, item);
  return result;
}

Where we iterate over the elements of an array and apply the reducingFunction on each one of them:

1
2
3
const sumAgain = reduce(magicNumbers, add);
console.log(`${magicNumbers.join(' + ')} = ${sum} (with our own reduce)`);
// => 1 + 2 + 3 + 4 = 10 (with our own reduce)

reduce doesn’t only work for adding an array of numbers, it’s the generalization of the idea of reducing a collection of values applying a reducing operation into a different value. We can use it for anything! Anything!?

For instance, finding the cheapest wand in a magic shop:

1
2
3
4
5
6
7
8
9
10
let shop = [
  {name: 'wand of fire', price: 100},
  {name: 'wand of ice', price: 200},
  {name: 'wand of healing', price: 50}
];

let cheapestWand = shop
  .reduce((item1, item2) => item1.price < item2.price ? item1 : item2)
console.log(`The cheapest wand is ${cheapestWand.name}`)
// => The cheapest wand is wand of healing

Or to filter wands under a given price:

1
2
3
4
5
6
7
8
// or to filter the wands under a given price
let cheapWands = shop
  .reduce((cheapWands, wand) => {
    if (wand.price <= 100) cheapWands.push(wand)
    return cheapWands;
   }, []);
console.log(`Cheap wands under 100 silvers: ${cheapWands.map(w => w.name)}`);
// => Cheap wands under 100 silvers: wand of fire, wand of healing

In the previous section, you also saw an example of a function that returns another function with add, addX and addXX. That means that we can jump directly to the next functional programming concept: Pure functions!

Pure Functions

A pure function is a completely deterministic function that has the following two characteristics:

  • Its result is only determined by its input values and is not affected by any state external to the function
  • It doesn’t have any side effects, that is, it doesn’t affect (change, mutate) any state external to the function

Because of these characteristics pure functions only operate on their arguments which makes them very easy to reason about, very testable and less error-prone. Following the same reasoning, programs built with pure functions share the same characteristics.

We already saw several pure functions in this article. The add function, for example, is a pure function:

1
const add = (a, b) => a + b;

The result of adding a plus b only depends on these inputs and it doesn’t matter how many times you add 1+1 it’s always going to be 2. Additionally, the function has no side effects, it doesn’t affect anything outside its boundaries.

On the other side of the fence we have impure functions which are very common in OOP languages. For instance, imagine that we have a WizardryShop class that represents a wizardry shop with all its wares, and bills and daily sales.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class WizardryShop {
  constructor(){
    this.items = new Map();
    this.coins = 0;
    this.sales = [];
  }
  addItemToInventory(item, units) {
    this.items.set(item, units)
  }
  sellItem(item, coins, date = new Date()) {
    this.items.set(item, this.items.get(item) - 1);
    this.coins += coins;
    this.sales.push({item, coins, date});
  }
  computeDailySales(date=new Date()){
    return this.sales
      .filter(s => s.date.toDateString() === date.toDateString())
      .reduce((total, sale) => total + sale.coins, 0);
  }
}

The method computeDailySales of a hypothetical wizardry shop is impure. It depends on the date argument but it does also depend on the state outside of the function. For any given date the result of computing daily sales will be different based on the state of the wizardryShop:

1
2
3
4
5
6
7
let wizardryShop = new WizardryShop();
wizardryShop.addItemToInventory('heal potion +50hp', 5);
wizardryShop.sellItem('heal potion +50hp', 20, new Date(2015, 10, 10));
wizardryShop.sellItem('heal potion +50hp', 20);
wizardryShop.sellItem('heal potion +50hp', 30);
console.log(`Sales today: ${wizardryShop.computeDailySales()} silvers`);
// => Sales today: 50 silvers

Why is this a problem from a functional programming perspective? Well, having an external dependency makes the function implementation more complex, it is harder to predict its behavior and harder to test, as we need to recreate the state for the complete wizardry shop object before we can test it.

Functional programming which comes from lambda calculus and the field of mathematics has a bias for using pure functions which is how functions work in mathematics and which is something good if you want to build robust programs.

It does have impure functions ocassionally though. For instance, the function returned by addXX is an impure function:

1
2
3
4
5
const addXX = function(x) {
  return function(b) {
    return add(x, b);
  }
}

That’s because the internal function has access to the x variable defined outside its boundaries. This is what we call a closure and is another tool often used in functional programming.

Closures

Closures are functions that enclose the values of free variables when they are created. A free variable is that one which is defined outside of the local scope of a function and in its lexical scope. Lexical Scope is the scoping scheme used in JavaScript where every inner scope has access to the outer scopes. Let’s illustrate all these concepts with an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// part of lexical scope of substractX
let cucumber = 'the cucumber';

const createSubstractX = function(x) {
  // part of lexical scope of substractX

  return function subtractX(a) {
    // local scope of substractX
    // variables in lexical scope:
    // - a: local variable
    // - x: free variable (enclosed)
    return add(a, -x);
  }
}

In this example we have a higher-order function createSubstractX that we can use to create other functions that substract a fixed number. The function substractX is a closure because it encloses the free variable x that lives in its lexical scope (just one level up).

The interesting thing about closures is that they have access to the enclosed variables even when the closure function is invoked outside their scope. The value of these enclosed variables will be set when the closure is created:

1
2
3
4
5
6
7
const substract5 = createSubstractX(5);
const substract10 = createSubstractX(10);

console.log(`10 - 5 = ${substract5(10)}`);
// => 10 - 5 = 5
console.log(`100 - 10 = ${substract10(100)}`);
// => 100 - 10 = 90

Now that you know about closures, let’s look at immutability!

But What is The Closure exactly?

In the wild, you’ll hear the term closure applied to several concepts: the function that encloses free variables, the technique of enclosing variables, the whole set of function and free variables that are enclosed, the wrapping function, etc.

The formal definition is that a closure is a function that captures the bindings of free variables in its lexical context. So in the previous example that would be subtractX.

Immutability

If you reflect about the different concepts that we have discussed so far you’ll realize that functional programming advocates strongly for a very deterministic and predictive style of programming where function results only depend on their inputs and where there are no side-effects. Another concept very natural to functional programming and in the same vein of pure functions is the concept of immutability or immutable data.

Immutable data is data that cannot be changed after it’s been created. The use of immutable data in your programs is yet another way to reduce coupling and side-effects. If your data cannot be changed after creation you are going to be a 100% sure that no function is going to alter that data and therefore your program will be easier to follow and less error-prone, particularly, from subtle bugs caused by coupling.

For instance, imagine that we have the WizardryShop from a previous example and we add a constructor so that you can initialize the shop with diverse wares and products:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class WizardryShopWithStartingItems {
  constructor(items){
    this.items = items; // now we can introduce some initial default items
    this.coins = 0;
    this.sales = [];
  }
  addItemToInventory(item, units) {
    this.items.push({item, units})
  }
  sellItem(item, coins, date = new Date()) {
    var idx = this.items.indexOf(item);
    if (idx === -1)
       throw Error(`Oh no! ${item} is sold out!`);

    this.items.splice(idx, 1); // remove item from catalog
    this.coins += coins;
    this.sales.push({item, coins, date});

    console.log(`${item} sold for ${coins} silvers`);
    return item;
  }
  computeDailySales(date=new Date()){
    return this.sales
      .filter(s => s.date.toDateString() === date.toDateString())
      .reduce((total, sale) => total + sale.coins, 0);
  }
}

Now we create two shops located in different parts of a hypothetical city:

1
2
3
4
5
6
7
8
let items = [
  'potion of healing +50hp',
  'potion of stamina +10sp',
  'potion of greater healing +500hp'
];

let theFlamingLantern = new WizardryShopWithStartingItems(items);
let theLightOfAdun = new WizardryShopWithStartingItems(items);

We have a hero that is in bad need of some healing potions so he goes around the city meaning to buy every single potion of greater healing there is. So he goes to the first shop and buys the potion:

1
2
theFlamingLantern.sellItem('potion of greater healing +500hp', 100);
// => potion of greater healing +500hp sold for 100 silvers

Everything is well and fine but when he goes to the second shop with the intent to buy the same potion:

1
2
3
4
5
6
try {
  theLightOfAdun.sellItem('potion of greater healing +500hp', 100);
} catch(error) {
  console.log(error.message);
  // => Oh no! potion of greater healing +500hp is sold out!
}

Everything crashes and burns. Both shops had access to the same mutable array and were inadvertedly coupled. We could’ve had a horrible bug present in our codebase for months and we wouldn’t have even noticed it! It would have slowly degraded the economy of our virtual kingdom and created a lot of unrest in the magic item selling community who would have thought that they were being plagued by thieves or evil curses.

If we had decided, however, to use an immutable data structure by using the Object.freeze method to make our array immutable:

1
2
3
4
5
6
 let immutableItems = [
  'potion of healing +50hp',
  'potion of stamina +10sp',
  'potion of greater healing +500hp'
  ];
  Object.freeze(immutableItems);

Then when we attempted to mutate the shared array:

1
2
3
4
5
6
7
8
9
10
11
12
13
  let theFlyingBoar = new WizardryShopWithStartingItems(immutableItems);
  let theLighthouseOfArda = new WizardryShopWithStartingItems(immutableItems);

  // our hero is in bad need of some healing potions
  // so he goes around the city meaning to buy every single healing potion there is
  try {
    theFlyingBoar.sellItem('potion of greater healing +500hp', 100);
    theLighthouseOfArda.sellItem('potion of greater healing +500hp', 100);
  } catch(error) {
    console.log(error.message);
    // => TypeError: Cannot add/remove sealed array elements
    // note that frozen objects only throw in strict mode
  }

We would have got alerted as to the fact that both shops are trying to mutate the same data structure. This would have helped prevent the nasty bug we were discussing above and let us take additional measures to ensure that mutation is encapsulated within the shop itself. For instance, it would point us to the necessity of cloning the starting array of items:

1
2
3
4
5
6
7
8
9
10
11
12
class WizardryShopWithStartingItems {
  constructor(items){
    this.items = clone(items);    // <== possible solution
    this.coins = 0;
    this.sales = [];
  }
  // etc
}

function clone(arr){
  return arr.slice(0, arr.length -1));
}

Immutable objects also have the boon of been thread-safe which is great in the world of parallel computing we’re increasingly living in today (Not a big use case for JavaScript that is single threaded but good to know anyhow).

We will take a look at immutability in greater detail later in another article with the challenges of immutable data in JavaScript and an introduction to immutable.js.

Concluding

Functional programming is a paradigm that seeks to simplify your programs by adding predictability and making them more readable using a declarative style that focuses on what and not on how.

Functional programming revolves around the idea of solving programmatic problems by creating abstractions through functions, and then combining these functions to create yet more high level abstractions and solve more challenging problems. As such, it relies heavily on the idea of functions as first class citizens of a language, functions that can be stored in a variable, or passed, or returned from another function.

Functions that get one or more functions as argument and/or return another function are known as higher-order functions. We saw a couple of examples of this type of functions with reduce and addX.

Pure functions are also an important concept in functional programming. They are functions whose result is only determined by their inputs, and which have no side-effects. The use of this type of functions results in a very easy-to-follow code base that is very testable.

Related to the concept of purity is the idea of immutable data. Using Immutable data gives you the assurance that no function is going to tamper with your data and therefore reduce side-effects and coupling. We illustrated this coupling problem with two magic shops which inventories were initialized with the same array.

Finally we discussed closures, as a common technique used with higher-order functions. Closures are functions that capture the value of free variables that live within their lexical scope.

With this introduction you now should be familiar with the most common functional programming concepts and ideas. In the next articles of these series we will reinforce these notions with more practical examples of functional programming and advice as to how you can use functional programming in your applications today. An excellent example of this is this article on LINQ and JavaScript.

Buy the Book!

Are you a C# Developer interested in learning JavaScript? Then take a look at the JavaScript-mancy book, a complete compendium of JavaScript for C# developers.

a JavaScriptmancy sample cover

Have a great week ahead!! :)

More Articles in These Series


  1. Also commonly known as fold in functional programming circles and as Aggregate in LINQ.

Comments