Mutable to immutable
Make a copy using the spread syntax that you can use to perform operations on. This is called a "shadow copy."
const grades = [10, 20];
const gradesCopy = [...grades];
console.log(gradesCopy); // [10, 20] (new array, not linked to 'grades')
Most array methods that you're familiar with will mutate the original array. For example, .push()
does mutate the array.
The same applies to lesser used methods such as .sort()
.
On the other hand, the ones that are immutable are .filter()
and .map()
because these methods return a new array (rather than modifying the old one). The .reduce()
method is also immutable since it returns a new value computed from an array.
const grades = [10, 20];
const updated = [...grades, 15];
console.log(updated); // [10, 20, 15] (new array, not related to 'grades')
console.log(grades); // [10, 20] (unchanged)
The reason why this works is that you're creating a new array with the [ ] syntax, and inside this array, you're spreading the items from grades and adding to it a new value which is 15.
You can also immutably update an array and immutably remove an item using the .map() and .filter() methods.
const grades = [10, 20, 15];
const updated = grades.filter(grade => grade !== 20);
console.log(updated); // [10, 15]
console.log(grades); // [10, 20, 15] (unchanged)
Try it
Complete the cloneApps function such that it returns a new copy of the apps parameter it receives.
// problem
const cloneApps = apps => {
}
// solution
const cloneApps = apps => {
const newapps = [...apps];
return newapps;
}
Try another one
Complete the function addApp such that it immutably adds the app parameter to the apps array it receives. This means that the original array should not be modified.
//problem
const addApp = (apps, app) => {
}
//solution
const addApp = (apps, app) => {
const newApps = [...apps, app];
return newApps
}
Immutable object operations
Same thing applies to objects
const user = {
id: 1,
age: 23
};
const cloned = {...user};
console.log(cloned); // {id: 1, age: 23} (new object not related to 'user')
Immutable add to an object
To add to an object, you need to make a copy of it and then add the new key:value to it
const user = {
id: 1,
age: 23
};
const clonedUser = {
...user,
age: user.age + 1
};
console.log(clonedUser); // {id: 1, age: 24} (new object not related to 'user')
console.log(user); // {id: 1, age: 23} (unchanged)
Immutable delete
The reason why this works is because {year, ...rest}
= book is destructuring the value of the key year from the book object. This is similar to reading book.year.
But...we then destructure the rest of the object with ...rest. This means combining all the other key/values in a new object called rest. So we end up with rest which is an immutable copy of book excluding the year property!
const book = {
id: 1,
title: "Harry Potter",
year: 2017,
rating: 4.5
}
// GOOD: immutable
const {year, ...rest} = book;
console.log(rest); // { id: 1, title: "Harry Potter", rating: 4.5}
console.log(book); // {id: 1, title: "Harry Potter", year: 2017, rating: 4.5} (unchanged)
Recap
- You can create a copy of an object using the ... operator:
{...originalObject}
- You can update an existing property:
{...originalObject, property: 'newValue'}
Try it
Complete the cloneConfig function such that it returns a new copy of the config parameter it receives.
//problem
const cloneConfig = config => {
}
//solution
const cloneConfig = config => {
const newConfig = {...config}
return newConfig;
}
//simplified
const cloneConfig = config => {
return {...config};
}
Try copying and changing something
//problem
const enableDarkTheme = config => {
}
//solution expanded
const enableDarkTheme = config => {
const newConfig = {...config}
newConfig.darkTheme= true;
return newConfig;
}
//simplified
const enableDarkTheme = config => {
return {...config, darkTheme: true};
}
Chapter Recap
- shallow copy = 1 level deep.
- You can create a shallow copy of an array using the spread syntax ...: [...originalArray].
- This works by spreading the items into a new array.
- You can immutably add an item to an array like this: [...originalArray, newItem]
- You can create a copy of an object using the ... operator:
{...originalObject}
- You can update an existing property:
{...originalObject, property: 'newValue'}
MDN Docs on structuredClone()