Dan D Kim

Let's share stories

Be careful when copying objects in Javascript

2020-03-16 Dan D. Kimjavascript

If you are going for a Javascript interview or going to start working in Javascript, you need to know how to copy objects in Javascript.

First, know that Javascript objects are stored by reference. Here’s an illustration:

const cat = {
  cry: 'meow'
}

const dog = cat
dog.cry = 'woof'

console.log(cat.cry) // woof

When dog is assigned to cat, we are just assigning the memory address of cat to dog. This is why changing dog.cry also changes cat.cry. Both cat and dog are pointing to the same memory address.

So, how do we copy objects?

Shallow copy

Here are two quick ways to shallow copy and object.

Spread Syntax

const cat = {
  cry: 'meow'
}

const dog = { ...cat }

Object.assign

const cat = {
  cry: 'meow'
}

const dog = Object.assign({}, cat)

But hold on, shallow copy only copies the first “layer” of the object. This means that any properties that are a reference to an object will give us the same problem we had in the first place.

Here’s what I mean:

const cat = {
  cry: 'meow',
  owner: {
    name: 'Dan'
  }
}

const dog = { ...cat }

dog.owner.name = 'Jake'

console.log(cat.owner.name) // Jake

cat.owner is an object, with its own memory address. By shallow copying cat, dog.owner shared the same memory address as cat.owner. This caused the problem where modifying dog.owner would also modify cat.owner. Yikes!

Let’s look at how we can do a deep copy.

Deep copy

Here’s how you can do a deep copy.

JSON.stringify and JSON.parse

const cat = {
  cry: 'meow',
  owner: {
    name: 'Dan'
  }
}

const dog = JSON.parse(JSON.stringify(cat))

JSON.stringify will convert the entire cat object into a string. And JSON.parse will convert that string back into an object, which means there aren’t any shared memory references with the original cat object!

However, there are some limitations:

  • Date objects are stringified and aren’t automatically converted back to Date objects
  • undefined properties are lost
  • Infinity is incorrectly set to null
  • RegEx properties are lost

If you need to use any of the above, consider using a utility library!

Lodash

Lodash is an awesome Javascript library full of utility functions. It is well-tested and used in many production modules!

It comes with the .clone() and .cloneDeep() function, which can do a shallow or a deep copy of an object (as the name says, duh).

const _ = require('lodash')

const cat = {
  cry: 'meow',
  owner: {
    name: 'Dan'
  }
}

const dog = _.cloneDeep(cat)

That’s all. Hope you learned something. Happy coding! :)