JavaScript is a flexible language, allowing for all sorts of styles and programming paradigms. Although this breadth sometimes comes at a cost to readability or consistency across a code base, it also allows developers to express their thoughts in different ways depending on the problem. One of those ways, functional programming, has become more and more popular with JavaScript programmers in recent years.
Functional programming relies on pure functions and avoids shared state and mutable data. It’s a programming style that rose to prominence with languages like Clojure, Scala, and Elm, but you can get into the functional mindset right within JavaScript. The following tips should help you to start writing more functional code and reap the benefits that the functional paradigm has to offer—functions that are easier to reason about, code that is easier to understand, and programs that are easier to test and debug.
The first step is embracing immutability. Ordinarily with JavaScript, you can change pretty much any variable you want. Any variable you declare can be reassigned to any other value, unless you use the const
keyword. Even then, if you declare a const
and assign it an object, you can change anything you want within the object itself. In functional programming, this is a big no-no. Mutations are considered a nasty side-effect that should be avoided. The issues that arise from mutation typically have to do with assumptions about shared state. For example, take the following code:
let myList = [1, 2, 3];
someFunction(myList);
console.log(myList);
If you’re using the full language functionality of JavaScript, you can make no assumptions about what is going to be logged to the console on line three. Instead you have to dig into the implementation of someFunction
to see what it does to myList
. But if we stick to the functional paradigm, we know that line three will log [1, 2, 3]
, because someFunction
isn’t allowed to mutate the list we passed in. If we want someFunction
to return some processed version of the list, we would have to return a new list with the processed values. The old list would remain the same:
let myList = [1, 2, 3];
let newList = mapToLetters(myList);
console.log(myList); // [1, 2, 3];
console.log(newList); // ['a', 'b', 'c'];