JavaScript is an easy to learn programming language. It also uses lots of functional programming features that make our lives easier.
In this article, we’ll look at some functional programming features of JavaScript, including functors and pure functions.
Functor
A functor is something that can be mapped over. If an entity’s entries can be mapped to new values, then it’s a functor.
In JavaScript, anything that we can call the map
method over is a functor. This would be an array in JavaScript.
For instance, with an array, we can call map
as follows:
const arr = [1, 2, 3].map(a => a * 2);
In the code above, we passed in a callback that returns an array with each value of the original array doubled. Therefore, an array is a functor.
In addition to arrays, we can create arrays by converting array-like iterable objects into arrays with the spread operator.
For instance, if we have a generator function:
const generator = function*() {
yield 1;
yield 2;
yield 3;
}
Then we can convert it to an array and call map
on the converted array as follows:
const arr = [...generator()].map(a => a * 2);
In the code above, we used the spread operator to convert the iterator returned by generator
into an array.
Then we get the same result as the first example.
Other examples of array-like iterable object include the arguments
object, DOM NodeLists, sets, maps, and the Files
object.
For non-iterable array-like objects. That is, objects that have numerical keys and the length
property, we can use Array.from
to convert it to an array.
We can call Array.from
as follows:
const obj = {
0: 1,
1: 2,
2: 3,
length: 3
}
const arr = Array.from(obj).map(a => a * 2);
In the code above, we passed obj
into Array.from
to convert it to an array, then call map
on it as we did in the previous examples.
Pure Functions
Pure functions are functions that always return the same output for a given set of inputs.
Also, they don’t produce any side effects. They’re useful because they’re easy to understand and test since they just manipulate inputs and return an output.
They also don’t commit any side effects so we don’t have things that happen outside the function itself that are caused by the function.
An example of a pure function includes:
const add = (x, y) => x + y;
The add
function just takes 2 numbers and return the result added together, so it’s a pure function. It doesn’t modify anything outside the function, so it commits no side effects.
An example of a function that’s not pure is something like:
let foo = 1;
const impureAdd = (a, b) => {
foo = 3;
return a + b;
};
The impureAdd
function commits a side effect by reassigning the foo
variable, which is outside the function to a different value.
Therefore, impureAdd
isn’t a pure function.
Side Effects
Side effects are any operation that’s observable outside the called function other than its returned value.
For instance, they include operations like:
- changing values of variables outside a function
- logging to the console
- drawing on the screen
- write file to disk
- run external processes
- calling other functions that commit side effects
- … and anything else that does things outside the function
With functional programming, side effects are minimized so that a function is easier to read and test as we don’t have to check their side effect results.
Referential Transparency
Referential transparency is the fact that an expression may be replaced by its value or anything having the same value without changing the result of the program.
The function should always return the same value for a given argument without having any other effect.
Also, this means that our functions have no side effects.
For instance, the add
function that we have above have referential transparency since we always get the same output for the same set of arguments passed in.
Conclusion
To make our code easy to read and test, we stick with pure functions as much as possible.
Side effects are avoided as possible so that we don’t have to deal with checking them.
Functors are anything that we can map their values over. In JavaScript, arrays have the map
method, so JavaScript arrays are functors. We can also convert many kinds of objects to arrays, including iterable and non-iterable array-like objects.