Buildtide
Author: Hussain Mir Ali

I am interested in web and mobile technologies.

If you have any questions or feedback then message me at devtips@Buildtide.com.

Immutables in JavaScript

One of the most crucial features of a programming language is immutability of object types. Immutability helps the developers to maintain application state with certainty. Since for most applications immutable objects are used for constraint definition. 

In ECMAScript-5 all the primitive object types are immutable which are 'string', 'number', 'undefined', 'boolean' and 'null'. Additionally in ECMAScript-6 there is a new primitive type called 'Symbol' which is also immutable.

The 'object' type is mutable in JavaScript and this can lead to unintended code behavior if preventive measures are not taken. The three most commonly used 'object' types in JavaScript are arrays, object literals and functions. 

Arrays:


let arra = [];
let arrb = arra.push('test_number_1');

console.log(arra);//['test_number_1']
console.log(arrb);//['test_number_1']

For the above code the objective to push 'test_number_1'  to only 'arrb' will not be achieved. This is because setting 'arrb' to modified version of 'arra' first alters 'arra' itself and then assigns the reference to 'arrb'. So 'arra' is the reference to the array object. 

To solve this issue first a new instance of 'arra' needs to be created and then 'test_number_1' will be pushed to that array and 'arra' will remain empty.

let arra= [];

//solution EcmaScript-5
let arrb = arra.slice();
arrb.push('test_number_1');

console.log(arra);//[]
console.log(arrb);//['test_number_1']

//solution EcmaScript-6
arrb = Array.from(arra);
arrb.push('test_number_1');

console.log(arra);//[]
console.log(arrb);//['test_number_1']

Object Literals:


let object_a = {};
let object_b = object_a;
object_b.status = 1;


console.log(object_a);//{status: 1}
console.log(object_b);//{status: 1}

In the sample code above it can be observed that changing the property of 'object_b' inadvertently changes the property of 'object_a'. This is because when 'object_a' is set to 'object_b' it has the reference to the original object and changing properties 'object_b' will then change the property of the reference object('object_a').

//solution1 in Ecmascript-5
var object_a={'status':5};
var object_b = {};

for(var property in object_a){
if(object_a.hasOwnProperty(property)){
object_b[property] = object_a[property];
}
}

object_b.status = 1;

console.log(object_a);//{status: 5}
console.log(object_b);//{status: 1}

The above solution-1 works best with shallow object literals which are one level deep.  First a copy of 'object_a' is created then the property 'status' is changed. In this case the original object 'object_a' remains the same and only 'object_b' affected.


//solution-2 in Ecmascript-5
var object_a=Object.freeze({'status':5});
var object_b = object_a;

object_b.status = 1;

console.log(object_a);//{status: 5}
console.log(object_b);//{status: 5}

The solution-2 implemented in the above code actually makes 'object_a' immutable using 'Object.freeze()' method. This way any accidental change of 'object_a' can be prevented.But it should be noted that 'Object.freeze()' method does not do deep freezing and this solution is best suited for shallow objects.


//Solution ECMAscript-6
let object_a={'status':5};
let object_b = Object.assign({}, object_a, {'status': 1});

object_b.status = 1;

console.log(object_a);//{status: 5}
console.log(object_b);//{status: 1}

ECMAScript-6 has a more elegant solution built into the language. Using 'Object.assign' method the old object can be assigned to a new object and any updates can also be passed as arguments. This way the 'object_b' doesn't have any reference to 'object_a' so any unintended behavior is avoided.

'const' in ECMAScript-6:

Variables that are declared as constants in EcmaScript-6 aren't actually immutable. The 'const' keyword is used to prevent re-binding of variable.

//Object literals
const settings = {'value': 1, 'color': 'blue'};

//unaltered object
console.log(settings);//{value: 1, color: 'blue'}

settings.value = 5;
settings.color = 'red';

//altered object
console.log(settings);//{value: 4, color: 'red'}


//Arrays
const info_arry = [1, 4, 4, 6, 234, 4, 1];

//unaltered object
console.log(info_arry);//[1, 4, 4, 6, 234, 4, 1]

info_arry[0] = 5;
info_arry[2] = 256;

//altered object
console.log(info_arry);//[5, 4, 256, 6, 234, 4, 1]

In the above example it is evident that the 'const' keyword does not make arrays or object literals immutable. So the 'const' keyword should be used with the right intention that is to prevent variable rebinding.