Array, mutability & immutability in JavaScript

Array, mutability & immutability in JavaScript

length()

  • The length property is used to find out the size of that object.

  • It’s used with many objects like JavaScript string, JavaScript array, etc.

let arr = ['Sparrow', 'Ostrich', 'Hawk', 'Parrot', 'Seagull', 'Blackbird', 'Penguin', 'Woodpecker']
console.log(arr.length);
// 8
let arrString = ‘helloWorld’;
console.log(arrString.length)
// 11
  • Every Array object has a length property whose value is always a non-negative integer less than 2²³ (i.e; 4294967296)
let arr = new Array(4294967296)
console.log(arr.length);
// RangeError: Invalid array length
let arr1 = new Array(-100)
console.log(arr1.length);
// RangeError: Invalid array length

In the above code, the value of arr is equal to 2²³ that’s why we’re getting the error “RangeError: Invalid array length”. To overcome the error we can set the array length less than 2²³ and as an array should be a non-negative integer that’s why we’re getting the error for arr1

  • When we extend an array by changing the length property than the number of actual element increases which causes the remain increased element to be a non-iterable empty slot.
let arr = [1, 2, 3, 4, 5, 6, 7]console.log(arr.length); 
// 7arr.length = 9;
console.log(arr) 
// [1, 2, 3, 4, 5, 6, 7, empty × 2]arr.forEach((elem => console.log(elem))); 
// 1
// 2
// 3
// 4
// 5
// 6
// 7

map()

  • It’s used to manipulate each and every array element of an array.

  • The map object holds key-value pairs and remembers the original insertion order of the keys. ~MDN

  • map() function is immutable (i.e; unalterable)

  • Immutable refers to the objects whose state can’t be changed once the object is created.

let myFirstName = "Elon";let myFullName = myFirstName.concat("Musk")

In the above code, myFullName equals to Elon Musk and myFirstName equals to Elon states that once the string value is created, it can never change.

  • No string methods change the string they operate on, they just return new strings. In fact, numbers, strings, and booleans all are immutable.
let mul = 5*7
console.log(mul)   //35
let mul = 5*7console.log(mul)   //35

In the above example output is 35 but the initial values (i.e; 5 and 7) doesn’t change.

Why immutable code is better than the mutable code in javascript?

An object whose state can be changed once the object is created is a mutable object while in case of an immutable object, the state can’t be changed once the object is created.

Now let’s take an example:

let games = {
  musicalChair :"indoor",
  caromPool :"indoor",
  cricket :"outdoor"
}// ----- IN CASE OF MUTABLE -----console.log(games)
// { musicalChair:"indoor", caromPool:"indoor", cricket:"outdoor" }// updating musical chair as outdoor game
games.musicalChair = "outdoor"console.log(games)
// { musicalChair:"outdoor", caromPool:"indoor", cricket:"outdoor" }// ----- IN CASE OF IMMUTABLE -----const {musicalChair, caromPool, cricket} = games
const updateGames = {
  musicalChair : "outdoor"
}console.log(updateGames)
// {musicalChair: "outdoor"}

In the above code what I had done is rather than changing the object property I created a whole new object.

What’s the benefit?

  • Immutability increases predictability

  • Allows for mutation tracking

  • Avoiding a reference clash

push() & pop()

  • push() helps to add items to the end of an array and returns the new length of an array.

  • pop() removes the last element of an array and returns that element.

  • In the case of an empty array or if the length of an array is 0, pop() returns undefined.

let birds = ['Sparrow', 'Ostrich', 'Hawk', 'Parrot']// ----- IN CASE OF push() -----//adding new element to an array
let updateBirds = birds.push('Blackbird', 'Penguin')
console.log(updateBirds)
// 6console.log(birds) 
//["Sparrow", "Ostrich", "Hawk", "Parrot", "Blackbird", "Penguin"]// ----- IN CASE OF pop() -----console.log(birds.pop());
// Parrot// in case of an empty array
let birds = []console.log(birds.pop());
// undefined

delete() & splice()

  • delete() used to delete object properties.

  • It won’t affect the length of an array.

let data = ["Sparrow", "cricket", "black", "kolkata"];// checking the length of data before deleting array element
console.log(data.length);  //4// deleting the third element i.e; "kolkata"
console.log(delete data[3]); //trueconsole.log(data);
// [ 'Sparrow', 'cricket', 'black', <1 empty item> ]// checking the length of data after deleting array element
console.log(data.length); //4

So, the conclusion is even after deleting the element the length of the array is the same as before.

To overcome with this bug we can use splice()

let data = ["Sparrow", "cricket", "black", "kolkata"];

// to delete the element from the mentioned index value i.e; "3" to the number of elements should've deleted i.e; "1"
data.splice(3,1)
console.log(data)
//[ 'Sparrow', 'cricket', 'black' ]console.log(data.length)
// 3

filter()

  • filter() method creates a new array with all elements that pass the test implemented by the provided function. ~MDN

  • It’s immutable and introduced in ES6

  • This method returns an array containing elements of the parent array that match the set test.

  • It has a single parameter, a callback method which triggered as the filter method iterates through the array elements.

let arr = [12, 23, 34, 54, 76, 36, 89]console.log(arr.filter(elem => elem > 50))
//[ 54, 76, 89 ]console.log(arr.filter(elem => elem > 90))
// []

In the above example, I took a test function (i.e; “> 50”) which returns a new array containing the elements that matched the set test.
But in case of next test function (i.e; “> 90”) returns an empty array because of no matches.

shift() & unshift()

  • shift() removes the element from the beginning of the array, returns the element that has been removed, update the indexes and the length property.

  • unshift() add the element to the beginning of an array. It mutates the original array and returns the length of the original array after mutation.

let names = ['Bill', 'Gates', 'Warren', 'Buffett']console.log(names.length)  //4// ----- IN CASE OF shift() -----console.log(names.shift());
// Bill// ----- IN CASE OF unshift() -----names.unshift('Elon', 'Musk');console.log(names);
// [ 'Elon', 'Musk', 'Bill', 'Gates', 'Warren', 'Buffett' ]console.log(names.length)  //6

reduce()

  • The reduce() method executes the reducer function on each element of the array, resulting in a single output value.

  • It comes with some terminologies like reducer and accumulator.

  • The reducer is what action we’ll perform in order to get one value.

  • The accumulator accumulates callbacks return values.

Let’s take an array calc and add all the numbers existing in the array:

let calc = [2, -4, 6, 8]
let sum = 0;// ----- IN SIMPLE ALGO -----for(let elem of calc) {
  sum += elem
}console.log(sum);
// 12// ----- USING reduce() METHOD -----sum = calc.reduce((accumulator, reducer) => {
  return accumulator + reducer;
}, 0)console.log(sum);
// 12

So this conclusion is, by using reduce() method we can reduce all the elements of the array into a single value. Where the single value can be a number/string/object.

reduceRight()

  • reduceRight() method reduces the array to a single value.

  • The reduceRight() method applies a function against an accumulator and each value of the array (from right-to-left) to reduce it to a single value. ~MDN

  • This method works in the same way as the reduce method, but in the opposite direction.

let arr = [ [ 3, 2, 6 ], [ 4, 8, 6 ], [ 9, 5 ] ]let newarr = arr.reduceRight((accumulator, reducer) => accumulator.concat(reducer));console.log(newarr);
// [ 9, 5, 4, 8, 6, 3, 2, 6 ]

NOTE: reduce() vs reduceRight()

reduce() method starts at the first element from left-to-right towards the last, whereas reduceRight() method starts at the first element from right-to-left towards the last.

let arr = ['1', '4', '6', '2', '9']let newArr1 = arr.reduce((accumulator, reducer) => accumulator + reducer)let newArr2 = arr.reduceRight((accumulator, reducer) => accumulator + reducer)console.log(newArr1);
//14629 (from left to right)console.log(newArr2);
//92641 (from right to left)