To understand object mutation in JavaScript it is important to understand the two groups of data types. Primitive and Non-primitive.


Primitive

A primitive data type is data that is not an object and has no methods or properties. These types are Immutable. The variable must be reassgined and cannot be changed. The 7 Data Types are:

  • string
  • number
  • bigint
  • boolean
  • undefined
  • symbol
  • null

See here for a more in depth description of the different primitive data types.

Non Primitive

These are objects and arrays. Here the the data is mutable. Changes can be made here and no new instance is created.

A Simple example of an Object:

const bigDinosaur = {name:"T-Rex"};

Understanding Mutations

const bigDinosaur = {name:"T-Rex", headSize: "Large", diet:"Carnivore"};
const smallDinosaur = bigDinosaur;

// Currently here both bigDinosaur and smallDinosaur are the same. 
console.log('Big Dino: ' + JSON.stringify(bigDinosaur) + " | Small Dino: " +  JSON.stringify(smallDinosaur));

// Lets change the smallDinosaur to something that makes more sense
smallDinosaur.name = "Microraptor";
smallDinosaur.headSize = "Small";

/*
Now when we print out both bigDinosaur and smallDinosaur 
 have taken on our new values.
 */
console.log('Big Dino: ' + JSON.stringify(bigDinosaur) + " | Small Dino: " +  JSON.stringify(smallDinosaur));

/* The above is happening because smallDinosaur is not a 
new instance it is actually just a reference to 
bigDinosaur so any changes will update the original reference
and both values will reflect that.*/

Preventing Mutation

Two ways that it can be prevented are:

The Assign Method

the object class has a method that copies properties from a source to a target object. providing an empty object as a target will ensure that we don't get a mutable object back.

const bigDinosaur = {name:"T-Rex"};
const smallDinosaur = {Object.assign({},bigDinosaur);
/*
Now smallDinosaur is no longer a reference but is a 
new instance. any changes made will not update the other variable
*/ 

The Spread

Spread syntax is much more simplistic and can be used in much that same way as the assign method.

const bigDinosaur = {name:"T-Rex"};
const smallDinosaur = {...bigDinosaur};

Full Example

const bigDinosaur = {name:"T-Rex", headSize: "Large", diet:"Carnivore"};
const smallDinosaur = {...bigDinosaur};

// Currently here both bigDinosaur and smallDinosaur are the same. 
console.log('Big Dino: ' + JSON.stringify(bigDinosaur) + 
" | Small Dino: " +  JSON.stringify(smallDinosaur));

// Lets change the smallDinosaur to something that makes more sense
smallDinosaur.name = "Microraptor";
smallDinosaur.headSize = "Small";

/*
Now only smallDinosaur have taken on our new values.
 */
console.log('Big Dino: ' + JSON.stringify(bigDinosaur) + 
" | Small Dino: " +  JSON.stringify(smallDinosaur));