|

Three ways to clone JavaScript Objects

Three ways to clone JavaScript Objects Photo by Tanner Yould on Unsplash

Three Ways to Clone JavaScript Objects

Objects in JavaScript carry reference values; you can’t simply copy an object using the equality operator =. But don’t worry! I’ll list here three ways for you to clone an object 💁

const drinks = { soda: '🥤', tea: '🍵' }

// Using the "Spread" syntax
{ ...drinks }

// Using the "Object.assign" method
Object.assign({}, drinks)

// Using "JSON" methods
JSON.parse(JSON.stringify(drinks))

// RESULT:
// { soda: '🥤', tea: '🍵' }

Objects are Reference Types

Perhaps the first question you might have is: why can’t I use =? Let’s see what happens if you do:

const obj = { abc: '123', def: '456' };

const obj2 = obj;

console.log(
  obj, // { abc: '123', def: '456' };
  obj2, // { abc: '123', def: '456' };
);

Up to this point, both objects seem to show the same thing. No issues, right? But let’s see what happens if we edit our second object:

obj2.ghi = '789';

console.log(obj2);
// { abc: '123', def: '456', ghi: '789' }; <-- 👌

console.log(obj);
// { abc: '123', def: '456', ghi: '789' }; <-- 🤦

WHAT?! I changed obj2, but obj was also affected. This happens because Objects are reference types. When you use =, it copies the reference to the memory space it occupies. Reference types don’t store values; they point to a value in memory.

If you want to learn more about this, I recommend reading the MDN article Working with Objects

1. Use the Spread (…) Syntax

Your object will be cloned using the spread syntax. However, note that this will be a shallow copy.

const drinks = { soda: '🥤', tea: '🍵' }

const cloneDrinks = { ...drinks };

console.log(cloneDrinks);
// { soda: '🥤', tea: '🍵' }

2. Use the Object.assign Method

The Object.assign method also creates a shallow copy of the object.

const drinks = { soda: '🥤', tea: '🍵' }

const cloneDrinks = Object.assign({}, drinks);

console.log(cloneDrinks);
// { soda: '🥤', tea: '🍵' }

Notice the empty object {} as the first argument; this will ensure the original object doesn’t suffer unwanted mutations 🧬

3. Use JSON Methods

This last method will generate a deep copy. This is a ‘quick and dirty’ way to clone an object deeply. You can use libraries like lodash or underscore for more robust solutions.

const drinks = { soda: '🥤', tea: '🍵' }

const cloneDrinks = JSON.parse(JSON.stringify(drinks));

console.log(cloneDrinks);
// { soda: '🥤', tea: '🍵' }

While this is a plausible solution, using JSON object methods can generate problems. If you have functions or Symbol type objects inside the object that will be cloned, they won’t behave as expected.

Shallow Copy vs. Deep Copy

When using spread ... to copy an object, only a shallow copy is being performed. If there are multidimensional or nested objects within the original object, the copy is not going to work as expected. Consider the following example:

const originalMonument = {
  symbol: '🗽',
  location: {
    city: 'New York',
    country: 'United States',
  },
};

Shallow Copy

Let’s clone our object using the spread operator:

const shallowClone = { ...originalMonument };

// We'll change our cloned object
shallowClone.symbol = '🕌';
shallowClone.location.city = 'Agra';
shallowClone.location.country = 'India';

We just changed the cloned object by changing the city and country properties. Let’s see what happens:

console.log(shallowClone);
// { symbol: '🕌', location: { city: 'Agra', country: 'India'} }

console.log(originalMonument);
// { symbol: '🕌', location: { city: 'Agra', country: 'India'} } <-- 😨

A shallow copy means that only the first level is copied. Deeper levels, like nested objects, are only referenced.

Deep Copy

Let’s use the same example, but this time with a deep copy using JSON

const deepClone = JSON.parse(JSON.stringify(originalMonument));

// Again, we'll change our cloned object
shallowClone.symbol = '🕌';
shallowClone.location.city = 'Agra';
shallowClone.location.country = 'India';

console.log(deepClone);
// { symbol: '🕌', location: { city: 'Agra', country: 'India'} }

console.log(originalMonument);
// { symbol: '🗽', location: { city: 'New York', country: 'United States'} } <-- 👌

As you can see, using JSON methods creates a real copy of the object, even with nested objects. Most of the time, a shallow copy is sufficient; you don’t need a deep copy all the time. You need to assess what each case requires and use the best tool for your situation. I hope this article has helped you clone objects using JavaScript.