Functional Programming in JavaScript: Functions, Composition and Currying

Fernando Doglio
Bits and Pieces
Published in
9 min readAug 11, 2020

--

Object-Oriented Programming and Functional Programming are two very distinct programming paradigms with their own rules and their own pros and cons.

However, JavaScript, instead of following one all the way down is sitting right in the middle of the two giving you some aspects of what a normal OOP language would have such as classes, objects, inheritance, and the like. But at the same time, it also provides you with some concepts of Functional Programming, such as higher-order functions and the ability to compose them as well.

So, while our favorite little language isn’t fully functional, I wanted to cover some of its aspects and how to use them to your advantage in JavaScript.

Tip: Use Bit (Github) to share, document, and manage reusable JS components from different projects. It’s a great way to increase code reuse, speed up development, and build apps that scale.

Higher-Order Functions

Let’s start by the most important of the three concepts I’m covering in this article: Higher Order Functions.

Having access to higher-order functions means functions are more than a construct you can define and call from your code, in fact, you can use them as assignable entities.

This should not come in as a surprise if you’ve done some JavaScript, after all, you should’ve been able to assign anonymous functions to constants simply from following examples online. Something like this is extremely common:

What might come as a surprise, especially if JavaScript is what you used to learn programming, is that the above logic is not valid in many other languages. Being able to assign a function as you would an integer is a very useful tool to have, in fact, most of the topics covered in this article are a by-product of that.

Benefits of HOF: encapsulating behavior

By having higher-order functions, we can not only assign functions like above but also, we can pass them as parameters on function calls. This, in turn, opens the door to create a very dynamic codebase where you can re-use complex behavior by directly passing it as an argument.

Imagine working on a purely Object Oriented environment and you’re looking to re-use a piece of logic that you understand can be extended and used as part of a greater code to achieve a task. In this case, you’d probably resort to using inheritance, by encapsulating that logic inside an abstract class and then extending it into a set of implementation classes that make use of that generic logic and add to it. That is perfect OOP behavior and it works, but let’s take a look at what we just did and why. We:

  • Created an abstract construct to encapsulate our re-usable logic.
  • Created a secondary construct
  • We made the latter extend the previous one in order to make use of it.

Now, all we wanted was to have the logic re-used, had we had access to a functional compatible environment, we could’ve simply extracted the re-usable logic into a function and then passed that function as a parameter to any other function that would benefit from using this encapsulated behavior. There is no “boilerplate” process just to re-use logic, we’re just creating functions.

The following examples try to show what I explained above. The first code shows how you would go about reusing a formatter logic in an OOP environment.

The second example, however, shows that by extracting the logic out into functions, you can mix and match to create exactly what you need with very little effort. You could continue adding more formatting and writing functions and then it would just be a matter of mixing them together with a single line of code:

Now, don’t get me wrong, both approaches have merit and both are extremely valid, there is no wrong here, I’m just showing you how incredibly flexible this approach is and how that is possible simply because we have the ability to pass behavior (i.e functions) as parameters as if they were a basic type such as an integer or a string.

Benefits of HOF: cleaner code

A great example of this is, of course, the Array methods, such as forEach , map , reduce, and so on. In non-functional programming compatible languages, such as C for instance, iterating over the elements of an array and applying a transformation to them requires the use of a for loop or some other loop structure. They require you to write code in a very imperative manner (in other words, you need to express how things happen inside the loop) while having the ability to use a functional approach allows for a more declarative type of coding (you end up specifying what needs to happen):

Your code is literally saying:

  • Declare a new variable i that will be used as the index for myArray and will have a value ranging from 0 to the number of items inside myArray .
  • On every value of i multiply the value of myArray at the position of i and add it to the transformedArray array.

It works and it’s relatively easy to understand, however, the logic can quickly escalate in complexity, and the cognitive load associated with reading it will increase as well. However, a functional approach like this might be easier to read:

Essentially, this code is saying:

  • Map the elements of myArray with the double function and assigned the result to transformedArray .

Much easier to read and because the logic is hidden away inside two functions ( map and double ) you don’t have to worry about understanding how they work. You could hide the multiplication logic inside a function on the first example as well, but the iteration logic needs to be there, and that is a big part of what you, as a human being reading the code, will have to mentally parse to understand how it is working.

Currying

Function currying is the act of turning a multi-parameter function into a function that receives less and has the extra parameters fixed. Let me explain with an example.

So now, if all you wanted to do was to add 10 to a series of values, you can call add10 instead of calling adder with the same second parameter every time. I know this might be a silly example and it’s probably the one you get everywhere when you look for currying, but considering what you’re doing: you’re taking the logic of the adder function and creating a specialized version of that function, in other words, you’re extending that function like you would with a class.

You can think of currying as the inheritance of functional programming, and following that line of thought and going back to the logger example, you can have something like this:

Essentially you have a function called log which needs three parameters and we’re currying it into specialized versions of itself that only require one, because the other two have already been picked by us.

It’s important to to note I’m treating the log function as an abtract class simply because in my example you wouldn’t want to use it directly, however there is no limitation to doing so, since this is just a normal function. If we were using classes, you wouldn’t be able to instantiate it directly.

Composition

Finally, function composition is another very interesting by-product of having higher-order functions available at our fingerprints. At a first glance, one could easily confuse composition as a case of currying, or maybe the other way around, having currying with functions instead of straight-up values (like we did in the logger example above) could be considered function composition.

And we would be almost right, there is a very fine line between both concepts when you start playing around with functions. In particular, a composition is defined as follows:

In computer science, function composition is an act or mechanism to combine simple functions to build more complicated ones. Like the usual composition of functions in mathematics, the result of each function is passed as the argument of the next, and the result of the last one is the result of the whole.

This is the definition of function composition taken from Wikipedia and the last bolded section was highlighted by me because that is the crucial part. With currying you don’t have that restriction, you can easily use the pre-set function parameters however you like, if they’re functions, they don’t have to be called one after the other having the results from the first one being the input for the second one and so on.

Now, this is a powerful tool because unlike with currying, where you had a function to be curried in the first place, here you only have partial functions, each fulfilling one particular task that is waiting to be composed into something much bigger and more complex. Think about this as if functions were lego blocks, and through composition, you’d be able to create whatever your imagination can come up with as long as you gran the right pieces and put them together in the right order (i.e as long as you compose the right functions in the right order).

If you’ve ever used a Linux distribution before, you might’ve noticed that CLI tools in Linux follow a very defined pattern: they do only one thing and are able to read from standard input and output their results to standard output. Thus, allowing users to compose multiple commands into one, for instance:

$ cat myfile.txt | wc -l

In that example, I’m reading a file and counting the number of lines it has, however, if combined differently or with other commands, the output can be drastically different. The same happens with functions if you design them in a way that the output of one can be the input of another you can also combine them like this.

Check out the above and final example, I created four different functions that deal with strings and composed them into three different ones. You can mix and match and get your own behaviors as well. That’s the beauty of composition.

Taking a closer look at the code, there are a few items of interest to cover:

  1. Some of the functions ( replace and findMatches ) actually take arguments and return a function. This is in order to make them more generic, thanks to the fact that JS saves the scope of the function being returned with the function itself (i.e closures) we’re able to have these parameters as “global” variables for the function being returned and used as part of the composition.
  2. Notice the compose function, it is taking advantage of ES6’s rest parameter, and simply iterating over them (i.e the functions we pass) and executing them and sending their results to the next one. The use of reduceRight ensures we compose from right to left on our list of functions, which is why I always added lowercase as the last one. If you wanted to have the order inversed, you could just use reduce instead.

Conclusion

I think that’s enough about functions for a day, don’t you? If used right, these higher-order functions and both currying and composition are very powerful tools. I know that if you’re not used to thinking about functions and instead you’d rather work with classes and objects, these techniques might seem counter intuitive, but they’re not inherently more complicated or difficult, it’s just a matter of changing your perspective.

Let the functional side of JavaScript take you over and enjoy it!

Have you used any of these tools before? Do you rather write code using a funcional approach? Or are you more of an OOP developer? Leave your comments down below, but try to not start a war, there is no right answer here!

Until then, see you on the next one!

--

--

I write about technology, freelancing and more. Check out my FREE newsletter if you’re into Software Development: https://fernandodoglio.substack.com/