How to Clone a JavaScript Object

Cloning an object in JavaScript is a common task for any project: from simple objects to complicated ones.

As a rule, the assignment operator doesn’t generate a copy of an object. It is capable of assigning a reference to it.

Let’s check out the following code:

let object = {
  a: 2,
  b: 3,
};
let copy = object;
object.a = 5;
console.log(copy.a);
// Result 
// a = 5;

The object variable is a container for a newly initialized object. The copy variable points to the same object and is a reference to the object. The object { a: 2, b: 3, } shows that there exist two ways of gaining success. This method can remove any form of immutability, leading to bugs.

There is a naive way to copy objects: it’s looping through the original one copying every property one after another. The code will look like this:

function copy(mainObject) {
  let objectCopy = {}; // objectCopy will store a copy of the mainObject
  let key;
  for (key in mainObject) {
    objectCopy[key] = mainObject[key]; // copies each property to the objectCopy object
  }
  return objectCopy;
}
const mainObject = {
  a: 1,
  b: 3,
  c: {
    x: 5,
    y: 4,
  },
}
console.log(copy(mainObject));

But note that there can be inherent issues, such as:

  • objectCopy obtains a new Object.prototype method that differs from mainObject object prototype method. But it’s not what you want if you wish a copy of the original object.
  • Property descriptors can not be copied. A “writable” descriptor, including a value set to be false, will be true within the objectCopy object.
  • The code that was shown above copies the enumerable properties of mainObject.
  • In case a property inside the original object is an object, it can be shared between the copy and the original one.

Notice that by nature, JavaScript objects are changeable and are stored as a reference. So, when assigning the object to another variable, you assign the memory address of the object to the variable. In such circumstances, the old and new objects point to the same memory address. Every change in one of them will be reflected in the other. Hence, assigning one object to another will not copy your object.

Shallow copy with Spread.Syntax or Object.assign

The spread syntax is one of the shortest and simplest methods of copying and/or merging objects.

The example will look as follows:

let obj = {
  key1: "value1",
  key2: "value2"
};
let clonedObject = { ...obj };
console.log(clonedObject);
// Object { key1: "value1", key2: "value2" }

The Object.assign() method is applied for copying all the enumerable properties from one or more source objects to the targeted object returning it.

Here is an example:

let obj = {
  key1: "value1",
  key2: "value2"
};
let clonedObject = Object.assign({}, obj);
console.log(clonedObject);
// Object { key1: "value1", key2: "value2" }

So, the spread syntax and object.assign are standard ways to copy an object. They are equivalent.

The problem with the methods above is that they implement a shallow copy. So, a new object is generated, which obtains the precise copy of the values of the original object. But notice that if any of the object fields is a reference to the other objects, simply the reference address is copied: only the memory address is copied.

The example is as follows:

let obj = {
  a: 0,
  b: {
    c: 0
  }
};
let copySpread = { ...obj };
let copyOA = Object.assign({}, obj);
console.log(JSON.stringify(obj)); // { a: 0, b: { c: 0}}
obj.a = 1;
console.log(JSON.stringify(obj)); // { a: 1, b: { c: 0}}
console.log(JSON.stringify(copySpread)); // { a: 0, b: { c: 0}}
console.log(JSON.stringify(copyOA)); // { a: 0, b: { c: 0}}
copySpread.a = 2;
copyOA.a = 3
console.log(JSON.stringify(obj)); // { a: 1, b: { c: 0}}
console.log(JSON.stringify(copySpread)); // { a: 2, b: { c: 0}}
console.log(JSON.stringify(copyOA)); // { a: 3, b: { c: 0}}
obj.b.c = 4;
console.log(JSON.stringify(obj)); // { a: 1, b: { c: 4}}
console.log(JSON.stringify(copySpread)); // { a: 2, b: { c: 4}}
console.log(JSON.stringify(copyOA)); // { a: 3, b: { c: 4}}

These methods are handy, but you are not recommended to use them when you have nested objects in the object that you want to copy.

Using JSON.stringify and JSON.parse

A deep copy takes place when you copy an object with the objects to which it refers. You can do it by applying the mixture of JSON.stringify and JSON.parse for creating a deep copy.

First of all you, should JSON.stringify() the json object parsing it to get the object back. The JSON.parse() method is targeted at parsing and constructing the JavaScript object or value that is described by the string. The new fields of the object have their memory address and are independent of nested object fields.

Here is an example of the deep cloning:

// Deep Clone
obj = {
  a: 0,
  b: {
    c: 0
  }
};
let cloneObj = JSON.parse(JSON.stringify(obj));
obj.a = 2;
obj.b.c = 2;
console.log(JSON.stringify(obj)); // { a: 2, b: { c: 2}}
console.log(JSON.stringify(cloneObj)); // { a: 0, b: { c: 0}}
cloneObj.a = 4;
cloneObj.b.c = 4;
console.log(JSON.stringify(obj)); // { a: 2, b: { c: 2}}
console.log(JSON.stringify(cloneObj)); // { a: 4, b: { c: 4}}

Describing JavaScript Objects

The purpose of the JavaScript objects is storing keyed collections of various data and more complicated entities.

JavaScript objects are included in all the language aspects; hence it is necessary to learn them as soon as you start to study it.

You can easily create objects using figure brackets {…} and having a list of properties is needed. Property is known as a “key: value”, in which key or property name is a string and value can be whatever.


Do you find this helpful?

Related articles