Writing Pure Functions

Hi everyone! In this post we’ll go over some ways to write pure functions.

So what exactly are pure functions?

Even if you may be unfamiliar with pure functions, the chances are that you have written one without realizing it. Rather than tell you about it, here is a brief example of Pure Function and Impure Function below:

Note: You may copy these codes and paste it into the compiler of your choice. Also, there is an embedded compiler with my code at the bottom of this post.

 

 

let mutate = 10;

function impureFunctionAdd(newValue) {

  return mutate += newValue;

}

impureFunctionAdd(5);

console.log('this is the mutated value: ', mutate);



let dontMutate = 20;

function pureFunctionAdd(newValue) {

  return dontMutate + newValue;

}

console.log('\npureFunctionAdd returns new value: ', pureFunctionAdd(22));

console.log('\nHowever, the variable remains unmutated: ', dontMutate);

 

 

Pure functions take in inputs (arguments) and returns a new value without having to permanently change variables outside of its scope. In the pure function above, we were able to retrieve a new value without altering the ‘dontMutate’ variable.

So why is pure function so important?

Pure functions promote maintainability and reusability; oppositely, impure function limits such qualities because when they mutate values outside of its scope, the side effect it causes can be undesirable. That in turn would promote  bug-ridden code.

Interestingly enough, React + Redux (which in my opinion is becoming the industry-standard Javascript framework/library) practices pure functions for its state management. Needless to say, developing a habit of writing pure function is important for easy transition into the framework.

 
 

Appending Arrays

 

Many of us (me included) would associate appending new elements to an array with its push function. Unfortunately, push is a mutating function. See below:

 

 

let mutateArray = [0, 1, 2];

function impureAppend(newValue) {

  return mutateArray.push(newValue);

}

impureAppend('mutated');

console.log('\nimpureAppend function mutated the value ', mutateArray);

 

 

Because the mutateArray’s value has changed, we have mutation. So what are ways to prevent them?

Here is a pure function approach to appending new value to array:

 

 

let dontMutateArray = [3, 4, 5];

function pureAppend(newValue) {

  return [

      ...dontMutateArray,

      newValue

  ];

}

console.log('\npureAppend returns new value: ', pureAppend('new value'));

console.log('\n...while keeping the variable unmutated: ', dontMutateArray);

 

 

…and we verify that it is a pure function because we return a new array without having to mutate the  original.

The 3 ‘dots’ in front of the variable dontMutateArray is called spread operator which was introduced in ES6. Please make sure if your environment has ES6 available. If that is not the case, concat is another method for your pure function.

 

 

let dontMutateArray = [3, 4, 5];

function pureAppendConcat(newValue) {

  return dontMutateArray.concat([newValue]);

}

console.log('\npureAppendConcat does the same thing: ', pureAppendConcat('new value'));

console.log('\n...see? -> ', dontMutateArray);

 

 

Injecting Arrays

 

Now, lets cover the basics of injecting a new element to array without having to mutate it.

Array’s splice is one of the impure functions we should watch out against:

let mutateInjection = [5, 6, 7];

function impureInject(index ,newValue) {

  return mutateInjection.splice(index, 0, newValue);

}

impureInject(2, 'mutate!');

console.log('\nimpureInject function mutated the value ', mutateInjection);

 

 

The pure function approach takes some creativity (but comes with extra fun!).

In this example, we concatenate the 3 sets of values into a new array by employing the slice function and the spread operator.

 

 

let dontMutateInjection = [6, 7, 8];

function pureInject(index,newValue) {

  return [

    ...dontMutateInjection.slice(0, index),

    newValue,

    ...dontMutateInjection.slice(index)

  ]

}

console.log('\npureInject returns new array ', pureInject(1, "Injected!"));

console.log('\n...while keeping the array the same: ', dontMutateInjection);

 

 

(Of course, if ES6 is not available, concat method must be used with slice function in similar fashion.)
 

 

Manipulating Objects

 

We’ve all been guilty of mutating objects. It’s really easy to do so:

 

 

let mutateObject = {

  'one': 1,

  'two': 2,

}

mutateObject.three = 3;

console.log('the object is mutated: ', mutateObject);

 

 

So here are some few ways to go about it. Just as Array uses the slice function, we can use the assign method and an empty object for the 1st argument, { }, to clone itself.

 

 

let dontMutateObject = {

  'one': 1,

  'two': 2

};

function pureInsert(newObj) {

  return Object.assign({}, dontMutateObject, newObj);

}

console.log('new object: ', pureInsert({tre: 3}));

console.log('original object: ', dontMutateObject);

 

 

Another method to adding new property is to use our new best friend: the spread operator.

 

 

console.log (‘spread operator’, {

...dontMutateObject, ‘tre’: 3

});;

console.log(‘keeps the original object intact: ‘, dontMutateObject);

 

 

It just so happens that spread operator is also very useful to overwrite the key/value of an object without resorting to mutation.

 

 

let dontEditObject = {

  'a': 1,

  'b': 2

};

console.log('create: ', {...dontEditObject, 'b': 'new value'});

console.log(‘original object: ’, dontEditObject);

 

 

We now how to add and edit to an object. How do we go about deleting them?

It certainly can be done with mutation function seen below:

 

 

let objImpureDelete = {
 'a': 1,
 'b': 2
};

delete objImpureDelete['a'];

console.log('objDelete: ', objImpureDelete);

 

 

But I hope we all learned by now that it is not the most proper way of doing so. One way that I know of is to use object de-structuring.

Object de-structuring works by creating new set of variables named after the name of the properties in the object. With the variables created, you can cherrypick the properties you want in a new object.

Please take care that none of the key names match with the previously declared variables!

 

 

let objPureDelete = {
 'a': 1,
 'b': 2,
 'c': 3,
 'd': 4
};

const { a, b, c, d } = objPureDelete;

const deleteA = {b, c, d};

console.log('delete a: ', deleteA);

console.log('objPureDelete: ', objPureDelete);

 

 

Thank you for reading this blog post! I see a great importance in practicing pure function because it helps us think differently in writing Javascript and promote less bug-ridden code. And of course,  having better understanding of the code we write as developers is always a good thing.

If you have any comments, questions, or some other tips/tricks to writing pure function that I have left out, please be sure to make a post below. I would love to learn more about them!

Until next time!
 

 

Next Post

Comments

See how we can help

Lets talk!

Stay up to date on the latest technologies

Join our mailing list, we promise not to spam.