JavaScript was created by Brendan Eich in May, 1995. He spent just ten days laying out the fundamental characteristics of the language. Like any project undertaken in a hurry, Eich borrowed ideas from other languages.
JavaScript took its syntax (and its name) from Java, which at the time was the hip new language. However, it gets much of its character from functional languages like Scheme, a language Eich particularly liked at the time.
Those features give JavaScript a special quality, an ability to combine and re-use functions like paint on a palette. In your Christmas stocking today, I’ll give you some classic functional techniques you can try to take advantage of this quality on even the smallest scale.
Purity
Functions receive inputs from their parameters, and give outputs using their return values. But functions can also have inputs and outputs that aren’t immediately obvious.
Here we have a function that sings “row, row, row your boat”. It takes the first line of the song, and logs it to the JavaScript console. It then waits a bit, and then repeats itself with the next line.
var song = [
'Row row row your boat',
'Gently down the stream',
'Merrily merrily merrily merrily',
'Life is but a dream'
];
function sing(lineNumber, colour) {
if (lineNumber > 3) return;
// Take the next line of the song
var line = song.splice(0, 1);
// Say it out loud
console.debug('%c ' + line, 'color: ' + colour);
// Wait a bit and repeat
setTimeout(() => {
sing(lineNumber + 1, colour)
}, 500);
}
sing(0);
When we run it, it sings us the lines of the song.
Like any good campfire songs, row row row your boat is good fun to sing with your friends. What happens if we try to run “sing” more than once?
sing(0, 'red');
setTimeout(() => { sing(0, 'gold') }, 500);
setTimeout(() => { sing(0, 'blue') }, 1000);
When we run the code, the first singer steals lines from the others before they can sing them. That doesn’t happen in real life!
“Sing” uses a function called “splice”. Splice returns items from the array that allows us to pick out the first line of the song, but it also has a side effect. It removes items from the original array, which makes our “sing” function remove lines of the song as it sings them.
We’ve written a function that is a bad citizen. The function changes data that doesn’t belong to it, and when it also depends on that data things go wrong. We call these actions “side effects” – when functions change data outside of their own scope.
var song = [
'Row row row your boat',
'Gently down the stream',
'Merrily merrily merrily merrily',
'Life is but a dream'
];
function sing(lines, colour) {
if (lines.length === 0) return;
console.debug('%c ' + lines[0], 'color: ' + colour);
setTimeout(() => {
sing(lines.slice(1, lines.length), colour)
}, 500);
}
sing(song, 'red');
setTimeout(() => { sing(song, 'gold') }, 500);
setTimeout(() => { sing(song, 'blue') }, 1000);
I’ve fixed the “sing” function to read the lines of the song using a parameter, and to use “slice” instead of “splice” which does not remove items from the original array. When we run our program again, all the lines should be sung as we’d expect.
Writing functions to work with their parameter inputs and their return outputs means they will always return the same output when given the same input and have no side effects. This is called “purity” by functional programmers because they are like functions in mathematics, but their benefits are plain to see:
By breaking code into simpler inputs and outputs, pure functions are easier to understand. They are testable, because they always give the same output for a given input. They are flexible, because they have no state of their own and can be used anywhere in your code.
Immutability
It’s unfortunate that JavaScript’s built-in functions incorporate hidden side-effects, because it makes using its functional features harder. Thankfully there is a way of working around this – immutable values.
Whereas JavaScript has built-in support for immutable values, using it is a faff so I recommend checking out Facebook’s Immutable.js library.
Immutable.js has a data structure like JavaScript’s arrays called “Lists”:
const Immutable = require('immutable');
const song = Immutable.List([
'Row row row your boat',
'Gently down the stream',
'Merrily merrily merrily merrily',
'Life is but a dream'
]);
Unlike normal arrays, their items cannot be changed at all. They remain the same from the point they are created until a new value is assigned or the scope they were created in is destroyed. The only way to make changes to items is by making new copies of the list:
const funnySong = song
.set(2, 'If you see a crocodile')
.set(3, 'don\'t forget to scream');
This leaves the original list intact, making side effects harder to introduce:
console.log(song);
List [
"Row row row your boat",
"Gently down the stream",
"Merrily merrily merrily merrily",
"Life is but a dream"
]
console.log(funnySong);
List [
"Row row row your boat",
"Gently down the stream",
"if you see a crocodile",
"don't forget to scream"
]
Immutable.js offers many methods and data structures to help you do practically anything you can do with native JavaScript arrays and objects, and more. In fact, when you’ve been using Immutable.js for a while its immutability features melt into the background and using is just like using a toolkit library like Underscore.js or Lodash. It really shines by encouraging us to write pure functions and to think carefully about how we work with data.
Currying
JavaScript’s functions are special – they can be passed to, and returned from other functions just like strings or numbers. This allows you to pre-program functions with settings you can use later.
Let’s look at a song called Old MacDonald Had a Farm. It goes like this:
var song = [
'Old McDonald had a farm',
'E I E I O',
'And on that farm he had a cow',
'E I E I O',
'With a moo moo here',
'And a moo moo there',
'Here a moo',
'There a moo',
'Everywhere a moo moo'
];
What if we wanted to sing the next verse with a dog instead of a cow? Let’s write a special function called a curried function to do that for us.
function curriedReplace(search, replace) {
return function(subject) {
return subject.replace(search, replace);
}
}
Currying allows you to write a function that is run in two stages. You call the function the first time to pre-program settings for later, such as text to search and replace. It then returns a function that can be called later to perform the searching and replacement. It’s really helpful when iterating over data and changing it – like changing words in a song.
var cowToDog = curriedReplace(/cow/g, 'dog');
When we call the function the first time, the settings we give it are saved for later. It doesn’t replace anything right away.
console.table(song.map(cowToDog));
0: "Old McDonald had a farm"
1: "E I E I O"
2: "And on that farm he had a dog"
3: "E I E I O"
4: "With a moo moo here"
5: "And a moo moo there"
6: "Here a moo"
7: "There a moo"
8: "Everywhere a moo moo"
When we pass it into map to iterate over the lines of the song, the second part of the function leaps into action and replaces the words using the settings we saved earlier.
This example might not seem like anything special on its own, and that’s okay. What is really magic is how functions allow you to re-use and combine code. Did you notice in my last example that we’ve replaced “cow” with “dog”, but the dog is saying “moo”? Let’s fix that.
Composition
Currying allows you compose a function out of two existing functions:
function compose(first, second) {
return function(subject) {
return second(first(subject));
}
}
This function takes two functions as settings, and returns a function for later use that combines them both. This allows us to compose a single function that replaces both the name of the animal, and the sound it makes without writing a new function especially to do that.
var cowToDog = curriedReplace(/cow/g, 'dog');
var mooToBark = curriedReplace(/moo/g, 'bark');
var changeToDog = compose(cowToDog, mooToBark);
Now if we run iterate over the lines of the song using this new function, we should see the correct result.
console.log(song.map(changeToDog));
0: "Old McDonald had a farm"
1: "E I E I O"
2: "And on that farm he had a dog"
3: "E I E I O"
4: "With a bark bark here"
5: "And a bark bark there"
6: "Here a bark"
7: "There a bark"
8: "Everywhere a bark bark"
Breaking down code into smaller, single-purpose functions has allowed us to combine and re-use them. This spares us the effort of writing, testing and maintaining lots of specialised functions. If we wanted to make a new function to replace “cow” with “chicken”, and “moo” with “cluck”, we can do this without having to write a suite of new unit tests.
Conclusion
The influence of functional programming on JavaScript makes it a delightful and expressive language to use. The techniques I have introduced not only allow you to keep your code simple, they also enable your code to become more than the sum of its parts. I hope they also illustrate that writing code in a functional way is not as hard as some would have you think! Merry Christmas and happy holidays.