Arrays, Objects and Mutations

What’s a mutation?

A mutation is a side effect: the fewer things that change in a program, the less there is to keep track of, which results in a simpler program.

Adding new elements to an array

  • Array.prototype.push
  • Array.prototype.unshift
  • Array.prototype.concat
  • Spread Operator (ES6)
const numbers = [1, 2];numbers.push(3); // results in numbers being [1, 2, 3]
const numbers = [2, 3];numbers.unshift(1); // results in numbers being [1, 2, 3]
const numbers = [1, 2];
const moreNumbers = numbers.slice();
moreNumbers.push(3);
const numbers = [1, 2];
const moreNumbers = numbers.concat([3]);
const people = [{ name: 'Bob' }, { name: 'Alice' }];
const morePeople = cloneDeep(people).concat([{ name: 'John' }]);
console.log(people[0] === morePeople[0]); // returns false
const numbers = [1, 2];
const moreNumbers = [...numbers, 3];
const positions = ['First', 'Second', 'Fifth', 'Sixth', 'Seventh'];positions.splice(2, 0, 'Third', 'Fourth');
const positions = ['First', 'Second', 'Fifth', 'Sixth', 'Seventh'];
const morePositions = positions
.slice(0, 2)
.concat(['Third', 'Fourth'])
.concat(positions.slice(2));
const positions = ['First', 'Second', 'Fifth', 'Sixth', 'Seventh'];
const morePositions = [
...positions.slice(0, 2),
'Third',
'Fourth',
...positions.slice(2)
];

Adding new properties to an object

  • Direct addition ❌
  • Object.assign (ES6) ✅
  • Object spread operator (experimental, not yet standardised) ✅
const person = { name: 'John Doe', email: 'john@doe.com' };// Using dot notation
person.age = 27;
// Using array notation
person['nationality'] = 'Irish';
const person = { name: 'John Doe', email: 'john@doe.com' };
const samePerson = Object.assign({}, person, {
age: 27,
nationality: 'Irish'
});
const person = { name: 'John Doe', email: 'john@doe.com' };
const samePerson = { ...person, age: 27, nationality: 'Irish' };

Removing elements from an array

  • Array.prototype.splice
  • Array.prototype.pop
  • Array.prototype.shift
  • Array.prototype.slice & Array.prototype.concat
  • Array.prototype.slice & the ES6 Spread Operator
  • Array.prototype.filter
const cities = ['Oslo', 'Rome', 'Cork', 'Paris', 'London', 'Bern'];cities.splice(2, 1); // removes 1 element from the 2nd index (Cork)
const cities = ['Oslo', 'Rome', 'Cork', 'Paris', 'London', 'Bern'];
const bern = cities.pop(); // removes Bern from the list of cities
const cities = ['Oslo', 'Rome', 'Cork', 'Paris', 'London', 'Bern'];
const oslo = cities.shift(); // removes Oslo from the list of cities
const cities = ['Oslo', 'Rome', 'Cork', 'Paris', 'London', 'Bern'];
const capitals = cities
.slice(0, 2)
.concat(cities.slice(3));
const cities = ['Oslo', 'Rome', 'Cork', 'Paris', 'London', 'Bern'];
const capitals = [
...cities.slice(0, 2),
...cities.slice(3)
];
const cities = ['Oslo', 'Rome', 'Cork', 'Paris', 'London', 'Bern'];
const capitals = cities.filter(city => city !== 'Cork');
const cities = ['Oslo', 'Rome', 'Cork', 'Paris', 'London', 'Bern'];
const capitals = cities.filter((city, index) => index !== 2);

Removing properties from an object

  • delete operator ❌
  • Object destructuring ✅
  • Lodash’s pick and omit
const person = { name: 'John Doe', email: 'john@doe.com', age: 27 };// dot notation
delete person.age;
// array notation
delete person['age'];
const person = {
name: 'John Doe',
email: 'john@doe.com',
age: 27,
country: 'Australia',
language: 'English',
profession: 'Front End Developer'
};
const { profession, country, ...newPerson } = person;console.log(newPerson);
const person = { name: 'John Doe', email: 'john@doe.com', age: 27 };
const fewerDetails = _.omit(person, 'age');
// or we could use pick which is the inverse of omit
const fewerDetails = _.pick(person, ['name', 'email']);

The takeaway

  • There are contexts in which mutation is not allowed (e.g. Redux reducers), but it’s fine in many other cases. This is why it’s essential to differentiate between observable and unobservable mutations. If you create an object in a function and then just need to populate it, it’s not very clever to try to avoid a mutation, let alone very inefficient. This thread is a good read on the topic.
  • Remember that the spread operator, Array.prototype.concat, Array.prototype.slice, etc. they only return a shallow copy of the array. If this is not good enough for your use case, use Lodash’s cloneDeep.
  • Also remember that returning a new array/object instead of mutating the original one, and particularly deep clones, are expensive in terms of performance. Just be aware that keeping data structures immutable comes with a price.

Credits

--

--

--

Front End Developer 👨‍💻

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Simple Web Apps using Basic CSS and JavaScript

Writing my Medium blog to complete account takeover

detect Browser and OS details using Playwright

Journey as a developer

React Tutorial — Build a Weather App from Scratch — Part 1

How to Debug Angular in Visual Studio Code

Top Ten Things Beginners Must Know About JavaScript for Interviews

Cross-repository Component Sharing using Mono-repo Multi-packages Architecture

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Federico Knüssel

Federico Knüssel

Front End Developer 👨‍💻

More from Medium

Add key-value pair to every object in array of objects in JavaScript

Check over, what exactly Promises in JavaScript?- Beginners Guide

JavaScript ES6: A crash course on modern JS

Javascript Testing In a Nutshell