Three Ways to Deep Clone Objects in JS – How to Clone Variables (The Clone Function) in Javascript?


JS Three Ways to Deep Clone Objects in JS - How to Clone Variables (The Clone Function) in Javascript?

NodeJs / Javascript

How to Deep Clone an Object in Javascript/NodeJs

There are three ways to clone an object/variable in Javascript/NodeJs: Recursive, JSON, and Message Channel.

Deep Clone Object using Recursive Algorithm

To Deep Copy a variable in Javascript, we have to first check its type – if it is an Array, we then need to clone each element in the array as a new copy and if it is an Object, we have to iterate the keys and assign a cloned copy (deep copy) to the new object. It is primitive type e.g. int, float, we can just return a value – copy by value.

function clone(Obj) {
  let buf; // the cloned object
  if (Obj instanceof Array) {
    buf = []; // create an empty array
    var i = Obj.length;
    while (i --) {
      buf[i] = clone(Obj[i]); // recursively clone the elements
    }
    return buf;
  } else if (Obj instanceof Object) {
    buf = {}; // create an empty object
    for (const k in Obj) {
      if (obj.hasOwnProperty(k)) { // filter out another array's index
        buf[k] = clone(Obj[k]); // recursively clone the value
      }     
    }
    return buf;
  } else {
    return Obj;
  }
}

Example usage:

var a = [1, 2, "abc", { "a" : [b, 3, 4] }, true];
var b = clone(a);

It should be noted that when cloning the elements of array, and the values in an Object, we have to recursively call the function to clone the value – as the element could be another array or Object, or any other types e.g. booleans – who knows how weird the Javascript can get.

However, this may not work for objects with recursive references, for example:

let obj = { a: 1 };
obj.b = obj
let obj2 = clone(obj);

VM657:13 Uncaught RangeError: Maximum call stack size exceeded
    at Object.hasOwnProperty (<anonymous>)
    at clone (<anonymous>:13:15)
    at clone (<anonymous>:14:18)
    at clone (<anonymous>:14:18)
    at clone (<anonymous>:14:18)
    at clone (<anonymous>:14:18)
    at clone (<anonymous>:14:18)
    at clone (<anonymous>:14:18)
    at clone (<anonymous>:14:18)
    at clone (<anonymous>:14:18)

We can fix this by using a Hash Map to remember the fields that we have cloned. Here is a correct version that clones an object even with recursive references:

function deepClone(obj) {
  const objectMap = new Map();
  const _deepClone = (value) => {
    const type = typeof value;
    if (type !== "object" || type === null) {
       return value;
    }
    if (objectMap.has(value)) {
       return objectMap.get(value);
    }
    const result = Array.isArray(value) ? [] : {};
    objectMap.set(value, result);
    for (const key in value) {
       result[key] = _deepClone(value[key]);
    }
    return result;
  };
  return _deepClone(obj);
}

Deep Clone Object using JSON parse/stringify

We can use the JSON parse/encode function to convert object to a string and then decode into the clone object.

function clone(obj) {
   return JSON.parse(JSON.stringify(obj));
}

However, this method does not support cloning the objects with recursive referecnes as well.

let obj = { a: 1 };
obj.b = obj
let obj2 = clone(obj);

VM1129:2 Uncaught TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Object'
    --- property 'b' closes the circle
    at JSON.stringify ()
    at clone (:2:27)
    at :3:12

Deep Clone Object using Message Channel

We can create a message channel via MessageChannel then we can create two ports which can communicate to each other. This is usually used with the Web-Worker.

So, we can send the object from one port to another. And then we can receive the object (as a clone) on the other port. We wrap this using Promise (Async Programming).

function deepClone(obj) {
  return new Promise((resolve) => {
    const { port1, port2 } = new MessageChannel();
    port1.postMessage(obj);
    port2.onmessage = (msg) => {
      resolve(msg.data);
    }
  }
}

This method supports cloning objects with self-references.

–EOF (The Ultimate Computing & Technology Blog) —

766 words
Last Post: How to restore SQL database backup by using SQL Server Management Studio?
Next Post: C# How to Remove Empty Elements from List in O(n)?

The Permanent URL is: Three Ways to Deep Clone Objects in JS – How to Clone Variables (The Clone Function) in Javascript? (AMP Version)

Leave a Reply