Different Ways to Duplicate Objects in JavaScript

Different Ways to Duplicate Objects in JavaScript

It turns out there are a lot of different ways to duplicate objects

In JavaScript, a variable can store two types of data:

  • Primitive
  • Reference

When we copy primitive values, only the value will be copied.

var a = 10;

When we copy primitive values, only values are copied.

But when we copy reference values, the memory address of the object is shared.

var a = { one : 1};

When we assign the object to other variables, only the memory address is copied.

Once we change the property of a or b, we are changing the value at the address of the object.

When the property of the object is changed, the changes are reflected in all variables pointing to the object.

If we want to copy a primitive value, we can use assignment operator (=), but for objects we cannot use the assignment operator.

When copying objects, there are two types:

  • Shallow copy
  • Deep copy

When we shallow-copy a source object to a target object, if the property value of the source object is primitive, then the value is copied to the target object. But if the property value of the source object is reference, then the reference is shared between the source and target objects.

In a deep copy, all the properties (including reference) of the source object are copied as values to the target object. There is no sharing of the reference between the source and target objects.

Difference between shallow and deep copy

Shallow Copy

Using the spread operator

var obj = {one : 1, two : 2};

var copiedObj = {...obj};

copiedObj.one = 3;

console.log(copiedObj.one); // 3

console.log(obj.one); // 1

The spread operator will copy all the enumerable properties of the obj to the copiedObj.

Using loop

function copy(sourceObj) {
  let targetObj = {}; 
  let keys = Object.keys(sourceObj);

  for (let i = 0, len = keys.length; i < len; i++) {
    let key = keys[i];
    targetObj[key] = sourceObj[key]; 
  }
  return targetObj;
}

This above code will loop through all the properties of the object and copy the value to the target object.

Object.assign

var source = {one : 1, nested: {two : 2}};

Deep Copy

Using JSON.stringify and JSON.parse

function JSONCopy(source) {
  return JSON.parse(JSON.stringify(source));
}

JSON.stringify and JSON.parse only work with number, string, and object literals and don’t support function or symbol properties.

Also, if the value of the property in the object is Date, then using JSON.stringify will convert the Date object to a string.

var a = { d : new Date() };

What is a circular object?

var a = {}; 

Circular objects are objects that have a property value referencing to themselves.

When we perform a deep copy of a circular object, it goes on endlessly. JSON.stringify/parse will throw an exception error when we perform a deep copy on a circular object.

We can use Object.assign to copy a circular object — but avoid creating a circular object in the first place.


Implementing Custom Clone

In the deepClone method, we will loop through all the properties of the object. If the value of the object is primitive, just copy it. If the value is reference, call the deepclone method.

function isObject(obj) {
  var type = typeof obj;
  return (type === 'function' || type === 'object') && !!obj; // this will handle obj , null and undefined
};

function deepClone(src) {
  let target = {};
  let keys = Object.keys(src);
  for (let i = 0, len = keys.length; i < len; i++ ) {
    let key = keys[i];
    if (src.hasOwnProperty(key)) {
      // if the value is a referece(object), recursively copy all properties by calling deepClone
      let val = src[key];
      let isObj = isObject(val);
      if (isObj) {
        target[key] = deepClone(val);
      } else {
        target[key] = val;
      }
    }
  }
  return target;
}
Deep clone in pure JavaScript

All the above methods only focus on objects, not arrays. They may not work for arrays.

Source: medium