Things you should know about Objects and Immutability in JavaScript

As a JavaScript developer, we should know that most things are objects – from core features, like strings and arrays, to the browser’s APIs. Here you can have a full introduction about objects in JavaScript.
JS’s objects are so beautiful: we can copy them, change and remove properties and do many cool things.

However, it’s always good to remember:

Ben Parker says to Peter Parker: With great power comes great responsibility.

What’s wrong with mutability?

That’s a question many developers have, and here a reasonable answer: there is nothing wrong if the code is mutable – the JavaScript’s Array API is and there’s nothing wrong with that. Yet, the misuse of mutability can cause side effects to your software. Here’s an example:


const user = {
  name: 'John Due',
  birthdate: '1988-08-15',
}

const changeName = (user, newName) => {
  const newUser = user
  newUser.name = newName
  return newUser
}

const userWithNewName = changeName(user, 'Jojo') 
// both users will have the name = 'Jojo'
console.log(user, userWithNewName) 

We can see that: although we are creating a new object, the user one was modified. This happens because when you assign a new value to an existing object, you are just assigning a memory reference to it.


const newUser = user

Come to the Immutable side of the force

Immutability is the art of maintaining the state of an object, making development simple, traceable, testable and decreasing any possible side effects. The main idea is: an update should not change the object, but create a new object with the updated data.

We can achieve immutability through pure functions, aka functions that will always return a given value if provided with the same input values. Neat, right? See this example:


const user = {
  name: 'John Due',
  birthdate: '1988-08-15',
}

const changeName = (user, newName) => {
  return {
    ...user, // destructuring user object
    name: newName, // override name attribute with new name
  }
}

const userWithNewName = changeName(user, 'Jojo')
// the old user object has name = 'John Due' and the new object, name = 'Jojo'
console.log(user, userWithNewName) 

Here we have a user object and its changeName function. You can see that, given the initial user and the new name, the initial object isn’t updated, and we always have the same result.

Creating Pure Functions and Removing References

Okay, we already know what can happen if we change the object’s state, now we need to know how to work with objects without causing side effects.

There are some ways to make immutable objects, but the most recommended approach to create them is using the Objects API and the ES6 destructuring assignment. We could also use functions like .map, .filter and .reduce to accomplish the same task.


// Example using Objects.assign
const changeName = (user, newName) => Object.assign({}, user, {
  name: newName
})

// Example using destructuring assignment
const changeName = (user, newName) => ({
  ...user,
  name: newName,
})

Wrapping up

When coding with JavaScript, manipulating objects is simple and practical, even though, it requires some care so your code does not end up bringing you headaches. Always remember to test your code to avoid unexpected mutation of objects.

There are some libraries that work pretty good with immutability, like ImmutableJS, Freezer and seamless-immutable.

Here at Cheesecake Labs we use Redux and ImmutableJS to accomplish pure and functional Front-end projects, keeping our code clean and easy to read.

Happy Coding!

About the author.

Daniel Leite
Daniel Leite

A Front-End developer passionate about open source culture. Trying to help people by sharing code.