A Complete Guide to Pure and Impure Functions in JavaScript

There are two popular terms you will encounter when working with functional programming in Javascript – Pure and Impure functions. It’s also a common topic you will likely come across in most Javascript interviews. On the surface level, the two might look quite similar. However, it would be best to have an in-depth understanding as a developer to get the most out of it.

An impure function is a function with one or more side effects. A pure function is a function without any side effects.

That definition might sound a bit too complex, especially if you don’t have a good understanding of “side effects” in programming. However, don’t panic! This post will give you a detailed guide on pure and impure functions, Side effects, why Side effects are necessary, and what you should watch out for when dealing with side effects.

What are Side Effects?

In functional programming, side effects occur when a function relies on or modifies an external code block outside its parameters to perform its operations. In other words, side effects occur when a function modifies a state outside its local scope.

Below are several examples that will help you have a solid understanding of side effects. This information will help you differentiate between a Pure and an Impure function.

Example 1: Add a New Value to an Old Value

Have a look at the code below.

var score = 0;

function addScore(newScore) { 
  return score += newScore; 
}

It is a simple code snippet that seems to be calculating scores. You need to take note of two things here: the var score = 0 variable and the addScore() function. Whenever the addNums() function is invoked, say addScore(5), it will need to read the value of the score variable, add the parameter passed to it (in this case, it’s 5), and return the new value of the score variable.

So what are the side effects present in this code?

Side Effect 1: Dependency on an External Value

In the code above, the addScore() function depends on the score value. If, in any case, the score variable is omitted or is “undefined,” the addScore() function will always return an error.

Side Effect 2: Modifies a Code Block Outside its Scope

When defining side effects above, this post said, “side effects occur when a function modifies a state outside its local scope.” In this scenario, the addScore() function is modifying the state of the score variable that is outside its local scope.

Side Effect 3: The Function is Unpredictable

When you look at the addScore() function alone, you can easily understand what it’s doing but cannot be sure of the output. It’s a non-deterministic function. That’s because there are external factors that determine its final result. In this case, the value of the score variable.

Example 2: Print Text to Console

Have a look at the code below.

function studentName() {
  console.log("My name is John Doe");
}

That is a simple function that prints the hard-coded name of the student. However, there is still a side effect to this function. The console.log() function. But how?

How Does the console.log() Cause a Side Effect?

The presence of a console.log() in a function changes the state of the application. Although you are not modifying any external data here, you are changing what is rendered on the screen. In short, you are modifying the current state of the application.

The console.log() does two things that make a function impure:

  • The function depends on the console.log() object to achieve its purpose.
  • The function is modifying the state of an external code block. In this case, it’s the console.log() object.

Other Examples of Side Effects

Other function operations considered as side effects include:

  • DOM manipulation. Modifying, removing, or adding elements to a website using Javascript is referred to as a side effect because it changes the website’s current state.
  • Making HTTP requests.
  • Modifying the value of a global variable.
  • Reading and Writing files.
  • Modifying the value of an argument.

Up to this point, you have learned what is a side effect in functional programming. With that information, you can now dive into Pure and Impure functions.

What is a Pure Function?

Pure functions are functions that do not have any side effects. They can also be termed as functions without an internal state. Therefore, any operation carried out by these functions is not dependent on the state. They are predictable functions; if given the same input, you can predict the result regardless of how many times you invoke the function.

Look at the example below.

function addScore(x,y) { 
  return x + y
}
console.log(`The Score is: ${addScore(12,15)}`)

A simple addScore() function calculates the score depending on the parameters passed. It does not depend on or modify any external code block. It is a predictable function. All these features make addScore() a pure function.

Always use pure functions in your code wherever possible. They don’t have a state and can share multiple instances in a class. Below are several advantages of using pure functions.

Advantages of Pure Functions

  • They are independent functions: Pure functions do not modify or depend on the state of an external code block. All the input used to perform operations is passed as parameters. There are no external factors that affect the operation of this function. It is predictable.
  • Easy to debug and read: Since pure functions don’t depend on any external code block or state, they are easy to debug and read. You only have to look within the function body, not any other code pieces.
  • Reusable: Pure functions can be easily reused in different sections of your code without altering its contents or the caller.

Things to Note When Working With Pure Functions

Now that you have a good understanding of pure functions in Javascript, there are a few things that you need to keep in mind.

Pure Functions allow Cloning of an External State.

In the definition, this post described pure functions as functions that do not modify any external state. Therefore, cloning/ copying an external state to a pure function doesn’t make it impure, as you only perform a copy-paste operation.

Take a look at the code below.

const score = [12,13];

function updateScore(newScore, array) {
  const clonedScore = [...array];
  clonedScore[clonedScore.length] = newScore;
  return clonedScore;
}

console.log(updateScore(17, score));

Here, the updateScore() function uses the spread operator to copy the contents of the score array into clonedScore array declared inside the function body. updateScore() is a pure function as it does not modify or depend on the state of the score array.

Avoid Code Mutations

Although you can change the state of a variable defined locally in a pure function, it is not recommended. Take a look at the code below.

const score = [12,13];

function updateScore(newScore, array) {
  const clonedScore = [...array];
  clonedScore[clonedScore.length] = newScore;
  return clonedScore;
}

console.log(updateScore(17, score));

The updateScore() function above is using clonedScore[clonedScore.length] = newScore to alter its state. Although that operation does not make updateScore() an impure function, it’s not the best practice.

The recommended way is to pass all the values as function parameters, as shown in the code below.

const score = [12,13];

function updateScore(newScore, array) {
  return [...array, newScore];
}

console.log(updateScore(17, score));

Simple and clear! The above code does the same thing as the previous one, but it’s now much simpler and easy to understand.

What is an Impure Function?

An impure function is unpredictable and contains one or more side effects. It’s a function that depends on or modifies data outside its lexical scope.

Take a look at the example below.

var score = 0;

function addScore(a,b){ 
  score = 5; 
  return a + b + score
}

console.log(addScore(10,15))

The score variable is declared outside the addScore() function scope and initially set to zero. However, its state is changed inside the addScore() function in the line score = 5. Automatically, the addScore() function becomes an impure function because it’s modifying the state of a code block outside its scope, making it have some side effects.

From the description, you can deduce that two main properties make a function impure.

  • It is unpredictable
  • It causes some side effects

Let’s look at one more example of an impure function that looks similar to a pure function. Take a look at the code below.

//IMPURE FUNCTION

const myArray = (arrOne, val) => {
  arrOne.push(val);
  return arrOne;
};

console.log(myArray([1, 2, 3], 4));
//Returns:  [1,2,3,4]

At first glance, this function appears to have no side effects, and one can easily conclude it as a pure function. However, take an in-depth look at this line – arrOne.push(val). Here, the myArray() function directly mutates the memory in place of the arrOne array. In short, it is modifying the original array passed to the function.

To achieve the same result with a pure function, you can use the spread operator to make a copy of the original array. Any operations done on this newly copied array won’t affect the original. See the code below.

//PURE FUNCTION

const myArray = (arrOne, val) => {
  return [...arrOne, val]
};

console.log(myArray([1, 2, 3], 4));
//Returns:  [1,2,3,4]

What if you were working with objects? Take a look at the code below.

//IMPURE FUNCTION

const myObject = (obj, key, val) => {
  obj[key] = val;
  return obj;
};
console.log(myObject({name:"John Doe"},"age",36));
//Returns:  { name: 'John Doe', age: 36 }

The myObject() function above is considered impure because it’s mutating the passed object parameter. Check this line – obj[key] = val.

To convert this to a pure function, you can use the spread operator, as shown below.

//PURE FUNCTION

const myObject = (obj, key, val) => {
  return {...obj,[key]:val};
};
console.log(myObject({name:"John Doe"},"age",36));
//Returns:  { name: 'John Doe', age: 36 }

In the above code, we copy the object’s contents and do not modify it directly.

Pure Methods in Javascript

Below are methods that are inherently considered pure in Javascript.

  • The spread ... operator used to create copies.
  • arr.map()
  • arr.filter()
  • arr.reduce()
  • arr.each()
  • arr.every()
  • arr.concat()
  • arr.slice()
  • Math.floor()
  • str.toLowerCase()

Impure Methods in Javascript

Below are methods that are inherently considered impure in Javascript.

  • Math.random(): This is regarded as an impure function because it produces a different result on each invocation.
  • Date.now()
  • arr.splice()
  • arr.push()
  • arr.sort()
  • Since Javascript is synchronous, asynchronous Javascript methods like fetch() and async() are also considered impure functions.

Comparison Between Pure and Impure Functions

So, which is which? Do you go with pure functions or impure functions?

There is no single winner between the two as they all play different roles in a program. For example, making DOM manipulations or HTTP requests with a pure function would be impossible. On the other hand, using too many impure functions in your code might easily result in Spaghetti Code, especially in large applications.

Below is a simple comparison table that will make it easier to differentiate between the two functions.

Pure FunctionsImpure Functions
Have no side effectsCause multiple side effects
They will always return the same result regardless of how many times the function is invoked.They return a different result on every successive function call.
They are easy to read and debugThey are hard to read and debug since they are affected by external code blocks.
They come in handy in certain contextsThey come in handy in certain contexts

Conclusion

This post has given you a detailed guide on pure and impure functions in Javascript. It has also looked at several examples and the advantages of using any of them. Pure functions are highly recommended as they are easy to read and debug.

Unfortunately, you cannot rely on them fully since there are operations they cannot perform. For example, DOM manipulations and making HTTP requests. In cases where you need to use impure functions, take note of the side effects to avoid any arising issues in your code.

Was this article helpful? Is there any additional information that you feel was left out?

You can also share your thoughts by replying on Twitter of Become A Better Programmer or to my personal account.