blog

  • Home
  • blog
  • Function Composition: Building Blocks for Maintainable Code

Function Composition: Building Blocks for Maintainable Code

One of the advantages of thinking about JavaScript in a functional way is the ability to build complex functionality using small, easy to understand individual functions. But sometimes that involves looking at a problem backwards instead of forwards in order to figure out how to create the most elegant solution.

In this article I’m going to employ a step-by-step approach to examine functional composition in JavaScript and demonstrate how it can result in code which is easier to reason about and which has fewer bugs.

Nesting Functions

Composition is a technique that allows you to take two or more simple functions, and combine them into a single, more complex function that performs each of the sub functions in a logical sequence on whatever data you pass in.

To get this result, you nest one function inside the other, and perform the operation of the outer function on the result of the inner function repeatedly until you produce a result. And the result can be different depending on the order in which the functions are applied.

This can be easily demonstrated using programming techniques we’re already familiar with in JavaScript by passing a function call as an argument to another function:

function addOne(x) {
  return x + 1;
}
function timesTwo(x) {
  return x * 2;
}
console.log(addOne(timesTwo(3))); //7
console.log(timesTwo(addOne(3))); //8

In this case we defined a function addOne() to add one to a value, and a timesTwo() function that multiplies a value by two. By passing the result of one function in as the argument for the other function, we can see how nesting one of these inside the other can produce different results, even with the same initial value. The inner function is performed first, and then the result is passed to the outer function.

Imperative Composition

If you wanted to perform the same sequence of operations repeatedly, it might be convenient to define a new function that automatically applied first one and then the other of the smaller functions. That might look something like this:

// ...previous function definitions from above
function addOneTimesTwo(x) {
  var holder = x;
  holder = addOne(holder);
  holder = timesTwo(holder);
  return holder;
}
console.log(addOneTimesTwo(3)); //8
console.log(addOneTimesTwo(4)); //10

What we’ve done in this case is manually compose these two functions together in a particular order. We created a new function that first assigns the value being passed to a holder variable, then updates the value of that variable by executing the first function, and then the second function, and finally returns the value of that holder.

(Note that we’re using a variable called holder to hold the value we’re passing in temporarily. With such a simple function, the extra local variable may seem redundant, but even in imperative JavaScript it’s a good practice to treat the value of arguments passed into a function as if they were constants. Modifying them is possible locally, but it introduces confusion about what the value of the argument is when it’s called at different stages within a function.)

Similarly, if we wanted to create another new function that applies these two smaller functions in the opposite order, we can do something like this:

Continue reading %Function Composition: Building Blocks for Maintainable Code%

LEAVE A REPLY