Understanding Functional Programming In JavaScript

Zak Frisch
8 min readNov 25, 2016

--

There has been a resurgence in the Functional Programming paradigm within JavaScript lately. As with most Technical concepts you might be hard-pressed to understand the jargon involved in its overly ridiculous definition.

The funny thing about the above definition is if I were to ask a potential hire about Functional Programming and they parroted that definition back to me, I would be quite stunned, and probably not in a positive way.

“Whatever cannot be said clearly is probably not being thought clearly either.”
— Peter Singer

Being a Programmer isn’t just about spouting out a sentence long string of niche Technical terms. It very often relies on your capability to explain an idea simply so that people not involved in that niche can understand it. That doesn’t mean it has to be an easy concept, but you certainly should not let how much you want to sound clever affect your explanations.

What is Functional Programming?

Functional Programming, as the name suggests, relies on a structuring mentality that all applications should be composed of functions instead of individually scripted one-time-use-only actions.

I know a lot of you out there probably just spoke the word “duh” aloud. Every programmer worth their salt should be working to make as many multi-use functions as possible in any application. This reduces the dreaded “spaghetti code” and can work to make all code more readable and, in turn, more manageable in the future.

It’s why this:

function addToBody(x) {
let createdNode = document.createTextNode(x);
document.body.appendChild(createdNode);
}
addToBody(‘hello ‘);
addToBody(‘world’);
addToBody(‘ my name is’);
addToBody(‘ zak frisch’);

Is preferred over this:

var createdNode = document.createTextNode(‘hello ‘);
document.body.appendChild(createdNode);
createdNode = document.createTextNode(‘world’);
document.body.appendChild(createdNode);
createdNode = document.createTextNode(‘ my name is’);
document.body.appendChild(createdNode);
createdNode = document.createTextNode(‘ zak frisch ‘);
document.body.appendChild(createdNode);

Obviously this is true. Based on the above examples you might find that this paradigm is pretty self-explanatory, and since you’re here reading this article you are most likely smart enough to know this already. What you may not know is that there are a few additional rules and guidelines to the Functional Programming paradigm beyond the obvious.

All work and no play

Rules:

  1. Functions should be stand alone blocks of code that can be tested and used individually. Nothing from a higher scope that’s not passed into a function should affect that function.
  2. The data provided to a function is not changed. A new value is created and returned.

What does that mean?

Let’s go through an example:

var global_arr = [‘a’,’b’,’c’];
//we want to add the next letter to the array
function pusher() {
global_arr.push(‘d’);
}
pusher();

First you may notice that global_arr is part of the global scope and, thus, aptly named. This is frowned upon in many instances but this isn’t an article about the modularity of code, so let’s pretend that extenuating circumstances have forced us to declare this array globally and ignore it.

What’s wrong with the code?

A big no-no of Functional Programming that is prevalent in our code is that within the function pusher we are changing data outside the function scope and adding an array item to a global variable(global_arr). We are directly manipulating global data.

How would we remake this to follow the Functional paradigm?

To the alarm of many Programmers experienced in using functions, it’s clear this function(pusher) isn’t worth the space it’s using up. First and foremost it isn’t reusable in the slightest, and on top of that it breaks our first rule.

We need to pass a variable into the function pusher to be used as our array. This will limit the passed in variable(arr) to the scope of the function pusher and allow for potential reuse.

var global_arr = [‘a’,’b’,’c’];function pusher(arr) {
arr.push(‘d’);
}
pusher(global_arr);

The second rule states that we are not allowed to change data and we must always return a new value. This is known as immutability — a technical term borrowed from the literal word meaning the inability to be changed. The technical term means the practice of not directly manipulating values. According to this rule we need to return a new value without manipulating the old value.

This may initially lead us to coding something similar to this:

var global_arr = [‘a’,’b’,’c’];function pusher(arr) {
arr.push(‘d’);
return arr;
}
pusher(global_arr);

This will not work and will lead to what’s called a Side Effect. Why?

Pen Prints out global_arr

The pen on the left runs the above code and then writes the value of global_arr to the screen.

It shows the values:
a,b,c,d
Even though it shouldn’t. You may have noticed that we never pushed anything to global_arr or explicitly changed its value.

This absolutely breaks our second rule.

Side Effects are no fun.

So how was global_arr changed? This happens because arrays(as well as objects) are passed as a reference to the original data. This means exactly what it sounds like it does. Any change to arr will directly manipulate global_arr even if we don’t want it to. This is a Side Effect — an unintended change in the application.

Another example can be found within an SO post In JavaScript, what does the term ‘side-effect’ refer to? in an answer written by JMar777:

I see it most commonly used to refer to some change in state outside of the immediate context. For example, the following code will cause no changes in state after execution, so it would be considered “side-effect free”:

(function() {
// no side-effects, foo won't exist once this function is done executing
var foo = 'bar';
})();

... whereas in the following code there are side-effects, because a global variable is introduced:

(function() {
// no var keyword, so global variable created
foo = 'bar';
})();

Our Side Effect is marginally different from the example code above but side effects don’t always follow the same formula. We are unintentionally adjusting a global variable, and that counts.

How can we fix this?

We would want to duplicate the value of arr while simultaneously cutting ties with its reference to global_arr. A common attempt at this may look like the following:

var global_arr = ['a','b','c'];function pusher(arr) {
let arr2 = arr;
arr2.push('d');
return arr2;
}
pusher(global_arr);

This too fails. The above code is simply accomplishing a reference from arr2 to arr1 to global_arr, effectively doing nothing to help our situation.

What we need to do is to clone the array and then manipulate and return the cloned value.

To clone an array you can use a few different techniques but by far the quickest and most prevalent would be to use the .slice array method or the ES6 spread operator.

array.slice Example:

clonedArr = arr.slice(0);

ES6 Spread Example:

clonedArr = [...arr];

Unfortunately browsers have yet to adopt all of ES6' capabilities. For the sake of compatibility our examples will use .slice but if you are intent on using ES6 just be aware that you may need to use a transpiler or polyfill to make it a cross-browser solution.

Our code using .slice:

var global_arr = ['a','b','c'];function pusher(arr) {
let clonedArr = arr.slice(0);
clonedArr.push('d');
return clonedArr;
}
pusher(global_arr);

As you can see the global_arr no longer prints out
a,b,c,d

This fixes our issue and clears us of any deviation from Functional Programming. It broke our program though since we don’t have anything adjusting global_arr value.

The last thing that we need to do to complete this little snippet of code is to adjust the global_arr so that it is properly changed to a,b,c,d. This is as simple as defining the value.

var global_arr = ['a','b','c'];function pusher(arr) {
let arr2 = arr.slice(0);
arr2.push('d');
return arr2;
}
global_arr = pusher(global_arr);

Rule 3

In our above example we created a simple and completely useless function call that followed the Functional Programming paradigm. We followed two rules:

  1. Functions should be stand alone blocks of code that can be tested and used individually. Nothing from a higher scope that’s not passed into a function should affect that function.
  2. The data provided to a function is not changed. A new value is created and returned.

But there is actually a third rule as well

3. Avoid loops…kind of

When it comes to Functional Programming we want to reduce everything we can to a function call. This includes our good friends, loops. This includes for…in,for…of,do…while, and while.

In order to do this a Programmer wishing to go full-on Functional is going to need to understand recursion — which is geek speak for a function calling itself.

For loop example:

function countDown(x) {
for (let i = x; i >= 0; i--) {
console.log(i);
}
}
countDown(10);

An example using recursion:

function countDown(n) {
console.log(n); //print a number to log
if(n > 0) countDown(n-1); //check condition to recurse
}
countDown(10); //10...9...8...7...6...5

Both of these examples work well enough. Neither of them break the first 2 rules of Functional Programming. Why, then, is it a rule to not use loops?

Good question.

While a functional language like Haskell uses recursion, an imperative language or a multi-paradigm language(such as JavaScript)can use loops. To stick with a completely pure Functional Programming paradigm you would not use loops because they can be written functionally. In other words, if you’re not dead set on changing all for loops to some form of recursive function, firstly you don’t have to. There’s not some magical code God watching over your shoulder to make sure you follow every paradigm exactly.

Secondly there are some purely functional iterators that are built straight into JavaScript that you can utilize.

Array.map() : The map() method creates a new array with the results of calling a provided function on every element in this array.

example:

var myArr = [1, 2, 3, 4];
var newArr = myArr.map(int => int + 1);
console.log(newArr); // 2,3,4,5

Array.reduce(): The reduce() method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.

example:

var myArr = [1, 2, 3, 4];
var sum = myArr.reduce((int, int2) => int + int2);
console.log(sum); // 10

Array.filter(): The filter() method creates a new array with all elements that pass the test implemented by the provided function.

example:

var myArr = [1, 2, 3, 4];
var filteredArr = myArr.filter((int) => int % 2 === 0);
console.log(filteredArr); // 2,4

That’s it! We’ve gone over the fundamentals. Hopefully you understand Functional Programming! If not, “Functional programming refers to the declarative evaluation of pure functions to create immutable programs by avoiding externally observable side effects.”

If that doesn’t help, please take a look at some of the resources listed below!

--

--