[javascript] How do I correctly clone a JavaScript object?

I have an object x. I'd like to copy it as object y, such that changes to y do not modify x. I realized that copying objects derived from built-in JavaScript objects will result in extra, unwanted properties. This isn't a problem, since I'm copying one of my own literal-constructed objects.

How do I correctly clone a JavaScript object?

This question is related to javascript clone javascript-objects

The answer is


Use deepcopy from npm. Works in both the browser and in node as an npm module...

https://www.npmjs.com/package/deepcopy

let a = deepcopy(b)


(The following was mainly an integration of @Maciej Bukowski, @A. Levy, @Jan Turon, @Redu's answers, and @LeviRoberts, @RobG's comments, many thanks to them!!!)

Deep copy? — YES! (mostly);
Shallow copy? — NO! (except Proxy).

I sincerely welcome everyone to test clone().
In addition, defineProp() is designed to easily and quickly (re)define or copy any type of descriptor.

Function

"use strict"
function clone(object) {
  /*
    Deep copy objects by value rather than by reference,
    exception: `Proxy`
  */

  const seen = new WeakMap()

  return clone(object)


  function clone(object) {
    if (object !== Object(object)) return object /*
    —— Check if the object belongs to a primitive data type */

    if (object instanceof Node) return object.cloneNode(true) /*
    —— Clone DOM trees */

    let _object // The clone of object

    switch (object.constructor) {
      case Array:
      case Object:
        _object = cloneObject(object)
        break

      case Date:
        _object = new Date(+object)
        break

      case Function:
        const fnStr = String(object)

        _object = new Function("return " +
          (/^(?!function |[^{]+?=>)[^(]+?\(/.test(fnStr)
            ? "function " : ""
          ) + fnStr
        )()

        copyPropDescs(_object, object)
        break

      case RegExp:
        _object = new RegExp(object)
        break

      default:
        switch (Object.prototype.toString.call(object.constructor)) {
          //                              // Stem from:
          case "[object Function]":       // `class`
          case "[object Undefined]":      // `Object.create(null)`
            _object = cloneObject(object)
            break

          default:                        // `Proxy`
            _object = object
        }
    }

    return _object
  }


  function cloneObject(object) {
    if (seen.has(object)) return seen.get(object) /*
    —— Handle recursive references (circular structures) */

    const _object = Array.isArray(object)
      ? []
      : Object.create(Object.getPrototypeOf(object)) /*
        —— Assign [[Prototype]] for inheritance */

    seen.set(object, _object) /*
    —— Make `_object` the associative mirror of `object` */

    Reflect.ownKeys(object).forEach(key =>
      defineProp(_object, key, { value: clone(object[key]) }, object)
    )

    return _object
  }


  function copyPropDescs(target, source) {
    Object.defineProperties(target,
      Object.getOwnPropertyDescriptors(source)
    )
  }
}


function defineProp(object, key, descriptor = {}, copyFrom = {}) {
  const { configurable: _configurable, writable: _writable }
    = Object.getOwnPropertyDescriptor(object, key)
    || { configurable: true, writable: true }

  const test = _configurable // Can redefine property
    && (_writable === undefined || _writable) // Can assign to property

  if (!test || arguments.length <= 2) return test

  const basisDesc = Object.getOwnPropertyDescriptor(copyFrom, key)
    || { configurable: true, writable: true } // Custom…
    || {}; // …or left to native default settings

  ["get", "set", "value", "writable", "enumerable", "configurable"]
    .forEach(attr =>
      descriptor[attr] === undefined &&
      (descriptor[attr] = basisDesc[attr])
    )

  const { get, set, value, writable, enumerable, configurable }
    = descriptor

  return Object.defineProperty(object, key, {
    enumerable, configurable, ...get || set
      ? { get, set } // Accessor descriptor
      : { value, writable } // Data descriptor
  })
}

// Tests

"use strict"
const obj0 = {
  u: undefined,
  nul: null,
  t: true,
  num: 9,
  str: "",
  sym: Symbol("symbol"),
  [Symbol("e")]: Math.E,
  arr: [[0], [1, 2]],
  d: new Date(),
  re: /f/g,
  get g() { return 0 },
  o: {
    n: 0,
    o: { f: function (...args) { } }
  },
  f: {
    getAccessorStr(object) {
      return []
        .concat(...
          Object.values(Object.getOwnPropertyDescriptors(object))
            .filter(desc => desc.writable === undefined)
            .map(desc => Object.values(desc))
        )
        .filter(prop => typeof prop === "function")
        .map(String)
    },
    f0: function f0() { },
    f1: function () { },
    f2: a => a / (a + 1),
    f3: () => 0,
    f4(params) { return param => param + params },
    f5: (a, b) => ({ c = 0 } = {}) => a + b + c
  }
}

defineProp(obj0, "s", { set(v) { this._s = v } })
defineProp(obj0.arr, "tint", { value: { is: "non-enumerable" } })
obj0.arr[0].name = "nested array"


let obj1 = clone(obj0)
obj1.o.n = 1
obj1.o.o.g = function g(a = 0, b = 0) { return a + b }
obj1.arr[1][1] = 3
obj1.d.setTime(+obj0.d + 60 * 1000)
obj1.arr.tint.is = "enumerable? no"
obj1.arr[0].name = "a nested arr"
defineProp(obj1, "s", { set(v) { this._s = v + 1 } })
defineProp(obj1.re, "multiline", { value: true })

console.log("\n\n" + "-".repeat(2 ** 6))




console.log(">:>: Test - Routinely")

console.log("obj0:\n ", JSON.stringify(obj0))
console.log("obj1:\n ", JSON.stringify(obj1))
console.log()

console.log("obj0:\n ", obj0)
console.log("obj1:\n ", obj1)
console.log()

console.log("obj0\n ",
  ".arr.tint:", obj0.arr.tint, "\n ",
  ".arr[0].name:", obj0.arr[0].name
)
console.log("obj1\n ",
  ".arr.tint:", obj1.arr.tint, "\n ",
  ".arr[0].name:", obj1.arr[0].name
)
console.log()

console.log("Accessor-type descriptor\n ",
  "of obj0:", obj0.f.getAccessorStr(obj0), "\n ",
  "of obj1:", obj1.f.getAccessorStr(obj1), "\n ",
  "set (obj0 & obj1) .s :", obj0.s = obj1.s = 0, "\n ",
  "  ? (obj0 , obj1) ._s:", obj0._s, ",", obj1._s
)

console.log("—— obj0 has not been interfered.")

console.log("\n\n" + "-".repeat(2 ** 6))




console.log(">:>: Test - Circular structures")

obj0.o.r = {}
obj0.o.r.recursion = obj0.o
obj0.arr[1] = obj0.arr

obj1 = clone(obj0)
console.log("obj0:\n ", obj0)
console.log("obj1:\n ", obj1)

console.log("Clear obj0's recursion:",
  obj0.o.r.recursion = null, obj0.arr[1] = 1
)
console.log(
  "obj0\n ",
  ".o.r:", obj0.o.r, "\n ",
  ".arr:", obj0.arr
)
console.log(
  "obj1\n ",
  ".o.r:", obj1.o.r, "\n ",
  ".arr:", obj1.arr
)
console.log("—— obj1 has not been interfered.")


console.log("\n\n" + "-".repeat(2 ** 6))




console.log(">:>: Test - Classes")

class Person {
  constructor(name) {
    this.name = name
  }
}

class Boy extends Person { }
Boy.prototype.sex = "M"

const boy0 = new Boy
boy0.hobby = { sport: "spaceflight" }

const boy1 = clone(boy0)
boy1.hobby.sport = "superluminal flight"

boy0.name = "one"
boy1.name = "neo"

console.log("boy0:\n ", boy0)
console.log("boy1:\n ", boy1)
console.log("boy1's prototype === boy0's:",
  Object.getPrototypeOf(boy1) === Object.getPrototypeOf(boy0)
)

References

  1. Object.create() | MDN
  2. Object.defineProperties() | MDN
  3. Enumerability and ownership of properties | MDN
  4. TypeError: cyclic object value | MDN

Language tricks used

  1. Conditionally add prop to object

Using Lodash:

var y = _.clone(x, true);

One particularly inelegant solution is to use JSON encoding to make deep copies of objects that do not have member methods. The methodology is to JSON encode your target object, then by decoding it, you get the copy you are looking for. You can decode as many times as you want to make as many copies as you need.

Of course, functions do not belong in JSON, so this only works for objects without member methods.

This methodology was perfect for my use case, since I'm storing JSON blobs in a key-value store, and when they are exposed as objects in a JavaScript API, each object actually contains a copy of the original state of the object so we can calculate the delta after the caller has mutated the exposed object.

var object1 = {key:"value"};
var object2 = object1;

object2 = JSON.stringify(object1);
object2 = JSON.parse(object2);

object2.key = "a change";
console.log(object1);// returns value

Here is a function you can use.

function clone(obj) {
    if(obj == null || typeof(obj) != 'object')
        return obj;    
    var temp = new obj.constructor(); 
    for(var key in obj)
        temp[key] = clone(obj[key]);    
    return temp;
}

With jQuery, you can shallow copy with extend:

var copiedObject = jQuery.extend({}, originalObject)

subsequent changes to the copiedObject will not affect the originalObject, and vice versa.

Or to make a deep copy:

var copiedObject = jQuery.extend(true, {}, originalObject)

For those using AngularJS, there is also direct method for cloning or extending of the objects in this library.

var destination = angular.copy(source);

or

angular.copy(source, destination);

More in angular.copy documentation...


I just wanted to add to all the Object.create solutions in this post, that this does not work in the desired way with nodejs.

In Firefox the result of

var a = {"test":"test"};
var b = Object.create(a);
console.log(b);´

is

{test:"test"}.

In nodejs it is

{}

For a deep copy and clone, JSON.stringify then JSON.parse the object:

obj = { a: 0 , b: { c: 0}};
let deepClone = JSON.parse(JSON.stringify(obj));
obj.a = 5;
obj.b.c = 5;
console.log(JSON.stringify(deepClone)); // { a: 0, b: { c: 0}}

Update 06 July 2020

There are three (3) ways to clone objects in JavaScript. As objects in JavaScript are reference values, you can't simply just copy using the =.

The ways are:

const food = { food: 'apple', drink: 'milk' }


// 1. Using the "Spread"
// ------------------

{ ...food }


// 2. Using "Object.assign"
// ------------------

Object.assign({}, food)


// 3. "JSON"
// ------------------

JSON.parse(JSON.stringify(food))

// RESULT:
// { food: 'apple', drink: 'milk' }

Hope that this can be used as a reference summary.


Performance

Today 2020.04.30 I perform tests of chosen solutions on Chrome v81.0, Safari v13.1 and Firefox v75.0 on MacOs High Sierra v10.13.6.

I focus on speed of copy DATA (object with simple type fields, not methods etc.). The solutions A-I can make only shallow copy, solutions J-U can make deep copy.

Results for shallow copy

  • solution {...obj} (A) is fastest on chrome and firefox and medium fast on safari
  • solution based on Object.assign (B) is fast on all browsers
  • jQuery (E) and lodash (F,G,H) solutions are medium/quite fast
  • solution JSON.parse/stringify (K) is quite slow
  • solutions D and U are slow on all browsers

enter image description here

Results for deep copy

  • solution Q is fastest on all browsers
  • jQuery (L) and lodash (J) are medium fast
  • solution JSON.parse/stringify (K) is quite slow
  • solution U is slowest on all browsers
  • lodash (J) and solution U crash on Chrome for 1000 level deep object

enter image description here

Details

For choosen solutions: A B C(my) D E F G H I J K L M N O P Q R S T U, I perform 4 tests

  • shallow-small: object with 10 non-nested fields - you can run it HERE
  • shallow-big: object with 1000 non-nested fields - you can run it HERE
  • deep-small: object with 10 levels-nested fields - you can run it HERE
  • deep-big: object with 1000 levels-nested fields - you can run it HERE

Objects used in tests are show in below snippet

_x000D_
_x000D_
let obj_ShallowSmall = {_x000D_
  field0: false,_x000D_
  field1: true,_x000D_
  field2: 1,_x000D_
  field3: 0,_x000D_
  field4: null,_x000D_
  field5: [],_x000D_
  field6: {},_x000D_
  field7: "text7",_x000D_
  field8: "text8",_x000D_
}_x000D_
_x000D_
let obj_DeepSmall = {_x000D_
  level0: {_x000D_
   level1: {_x000D_
    level2: {_x000D_
     level3: {_x000D_
      level4: {_x000D_
       level5: {_x000D_
        level6: {_x000D_
         level7: {_x000D_
          level8: {_x000D_
           level9: [[[[[[[[[['abc']]]]]]]]]],_x000D_
  }}}}}}}}},_x000D_
};_x000D_
_x000D_
let obj_ShallowBig = Array(1000).fill(0).reduce((a,c,i) => (a['field'+i]=getField(i),a) ,{});_x000D_
_x000D_
_x000D_
let obj_DeepBig = genDeepObject(1000);_x000D_
_x000D_
_x000D_
_x000D_
// ------------------_x000D_
// Show objects_x000D_
// ------------------_x000D_
_x000D_
console.log('obj_ShallowSmall:',JSON.stringify(obj_ShallowSmall));_x000D_
console.log('obj_DeepSmall:',JSON.stringify(obj_DeepSmall));_x000D_
console.log('obj_ShallowBig:',JSON.stringify(obj_ShallowBig));_x000D_
console.log('obj_DeepBig:',JSON.stringify(obj_DeepBig));_x000D_
_x000D_
_x000D_
_x000D_
_x000D_
// ------------------_x000D_
// HELPERS_x000D_
// ------------------_x000D_
_x000D_
function getField(k) {_x000D_
  let i=k%10;_x000D_
  if(i==0) return false;_x000D_
  if(i==1) return true;_x000D_
  if(i==2) return k;_x000D_
  if(i==3) return 0;_x000D_
  if(i==4) return null;_x000D_
  if(i==5) return [];_x000D_
  if(i==6) return {};  _x000D_
  if(i>=7) return "text"+k;_x000D_
}_x000D_
_x000D_
function genDeepObject(N) {_x000D_
  // generate: {level0:{level1:{...levelN: {end:[[[...N-times...['abc']...]]] }}}...}}}_x000D_
  let obj={};_x000D_
  let o=obj;_x000D_
  let arr = [];_x000D_
  let a=arr;_x000D_
_x000D_
  for(let i=0; i<N; i++) {_x000D_
    o['level'+i]={};_x000D_
    o=o['level'+i];_x000D_
    let aa=[];_x000D_
    a.push(aa);_x000D_
    a=aa;_x000D_
  }_x000D_
_x000D_
  a[0]='abc';_x000D_
  o['end']=arr;_x000D_
  return obj;_x000D_
}
_x000D_
_x000D_
_x000D_

Below snippet presents tested solutions and shows differences between them

_x000D_
_x000D_
function A(obj) {_x000D_
  return {...obj}_x000D_
}_x000D_
_x000D_
function B(obj) {_x000D_
  return Object.assign({}, obj); _x000D_
}_x000D_
_x000D_
function C(obj) {_x000D_
  return Object.keys(obj).reduce( (a,c) => (a[c]=obj[c], a), {})_x000D_
}_x000D_
_x000D_
function D(obj) {_x000D_
  let copyOfObject = {};_x000D_
  Object.defineProperties(copyOfObject, Object.getOwnPropertyDescriptors(obj));_x000D_
  return copyOfObject;_x000D_
}_x000D_
_x000D_
function E(obj) {_x000D_
  return jQuery.extend({}, obj) // shallow_x000D_
}_x000D_
_x000D_
function F(obj) {_x000D_
  return _.clone(obj);_x000D_
}_x000D_
_x000D_
function G(obj) {_x000D_
  return _.clone(obj,true);_x000D_
}_x000D_
_x000D_
function H(obj) {_x000D_
  return _.extend({},obj);_x000D_
}_x000D_
_x000D_
function I(obj) {_x000D_
    if (null == obj || "object" != typeof obj) return obj;_x000D_
    var copy = obj.constructor();_x000D_
    for (var attr in obj) {_x000D_
        if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];_x000D_
    }_x000D_
    return copy;_x000D_
}_x000D_
_x000D_
function J(obj) {_x000D_
  return _.cloneDeep(obj,true);_x000D_
}_x000D_
_x000D_
function K(obj) {_x000D_
 return JSON.parse(JSON.stringify(obj));_x000D_
}_x000D_
_x000D_
function L(obj) {_x000D_
  return jQuery.extend(true, {}, obj) // deep_x000D_
}_x000D_
_x000D_
function M(obj) {_x000D_
  if(obj == null || typeof(obj) != 'object')_x000D_
    return obj;    _x000D_
  var temp = new obj.constructor(); _x000D_
  for(var key in obj)_x000D_
    temp[key] = M(obj[key]);    _x000D_
  return temp;_x000D_
}_x000D_
_x000D_
function N(obj) {_x000D_
  let EClone = function(obj) {_x000D_
    var newObj = (obj instanceof Array) ? [] : {};_x000D_
    for (var i in obj) {_x000D_
      if (i == 'EClone') continue;_x000D_
      if (obj[i] && typeof obj[i] == "object") {_x000D_
        newObj[i] = EClone(obj[i]);_x000D_
      } else newObj[i] = obj[i]_x000D_
    } return newObj;_x000D_
  };_x000D_
_x000D_
 return EClone(obj);_x000D_
};_x000D_
_x000D_
function O(obj) {_x000D_
    if (obj == null || typeof obj != "object") return obj;_x000D_
    if (obj.constructor != Object && obj.constructor != Array) return obj;_x000D_
    if (obj.constructor == Date || obj.constructor == RegExp || obj.constructor == Function ||_x000D_
        obj.constructor == String || obj.constructor == Number || obj.constructor == Boolean)_x000D_
        return new obj.constructor(obj);_x000D_
_x000D_
    let to = new obj.constructor();_x000D_
_x000D_
    for (var name in obj)_x000D_
    {_x000D_
        to[name] = typeof to[name] == "undefined" ? O(obj[name], null) : to[name];_x000D_
    }_x000D_
_x000D_
    return to;_x000D_
}_x000D_
_x000D_
function P(obj) {_x000D_
  function clone(target, source){_x000D_
_x000D_
      for(let key in source){_x000D_
_x000D_
          // Use getOwnPropertyDescriptor instead of source[key] to prevent from trigering setter/getter._x000D_
          let descriptor = Object.getOwnPropertyDescriptor(source, key);_x000D_
          if(descriptor.value instanceof String){_x000D_
              target[key] = new String(descriptor.value);_x000D_
          }_x000D_
          else if(descriptor.value instanceof Array){_x000D_
              target[key] = clone([], descriptor.value);_x000D_
          }_x000D_
          else if(descriptor.value instanceof Object){_x000D_
              let prototype = Reflect.getPrototypeOf(descriptor.value);_x000D_
              let cloneObject = clone({}, descriptor.value);_x000D_
              Reflect.setPrototypeOf(cloneObject, prototype);_x000D_
              target[key] = cloneObject;_x000D_
          }_x000D_
          else {_x000D_
              Object.defineProperty(target, key, descriptor);_x000D_
          }_x000D_
      }_x000D_
      let prototype = Reflect.getPrototypeOf(source);_x000D_
      Reflect.setPrototypeOf(target, prototype);_x000D_
      return target;_x000D_
  }_x000D_
  return clone({},obj);_x000D_
}_x000D_
_x000D_
function Q(obj) {_x000D_
    var copy;_x000D_
_x000D_
    // Handle the 3 simple types, and null or undefined_x000D_
    if (null == obj || "object" != typeof obj) return obj;_x000D_
_x000D_
    // Handle Date_x000D_
    if (obj instanceof Date) {_x000D_
        copy = new Date();_x000D_
        copy.setTime(obj.getTime());_x000D_
        return copy;_x000D_
    }_x000D_
_x000D_
    // Handle Array_x000D_
    if (obj instanceof Array) {_x000D_
        copy = [];_x000D_
        for (var i = 0, len = obj.length; i < len; i++) {_x000D_
            copy[i] = Q(obj[i]);_x000D_
        }_x000D_
        return copy;_x000D_
    }_x000D_
_x000D_
    // Handle Object_x000D_
    if (obj instanceof Object) {_x000D_
        copy = {};_x000D_
        for (var attr in obj) {_x000D_
            if (obj.hasOwnProperty(attr)) copy[attr] = Q(obj[attr]);_x000D_
        }_x000D_
        return copy;_x000D_
    }_x000D_
_x000D_
    throw new Error("Unable to copy obj! Its type isn't supported.");_x000D_
}_x000D_
_x000D_
function R(obj) {_x000D_
    const gdcc = "__getDeepCircularCopy__";_x000D_
    if (obj !== Object(obj)) {_x000D_
        return obj; // primitive value_x000D_
    }_x000D_
_x000D_
    var set = gdcc in obj,_x000D_
        cache = obj[gdcc],_x000D_
        result;_x000D_
    if (set && typeof cache == "function") {_x000D_
        return cache();_x000D_
    }_x000D_
    // else_x000D_
    obj[gdcc] = function() { return result; }; // overwrite_x000D_
    if (obj instanceof Array) {_x000D_
        result = [];_x000D_
        for (var i=0; i<obj.length; i++) {_x000D_
            result[i] = R(obj[i]);_x000D_
        }_x000D_
    } else {_x000D_
        result = {};_x000D_
        for (var prop in obj)_x000D_
            if (prop != gdcc)_x000D_
                result[prop] = R(obj[prop]);_x000D_
            else if (set)_x000D_
                result[prop] = R(cache);_x000D_
    }_x000D_
    if (set) {_x000D_
        obj[gdcc] = cache; // reset_x000D_
    } else {_x000D_
        delete obj[gdcc]; // unset again_x000D_
    }_x000D_
    return result;_x000D_
}_x000D_
_x000D_
function S(obj) {_x000D_
    const cache = new WeakMap(); // Map of old - new references_x000D_
_x000D_
    function copy(object) {_x000D_
        if (typeof object !== 'object' ||_x000D_
            object === null ||_x000D_
            object instanceof HTMLElement_x000D_
        )_x000D_
            return object; // primitive value or HTMLElement_x000D_
_x000D_
        if (object instanceof Date) _x000D_
            return new Date().setTime(object.getTime());_x000D_
_x000D_
        if (object instanceof RegExp) _x000D_
            return new RegExp(object.source, object.flags);_x000D_
_x000D_
        if (cache.has(object)) _x000D_
            return cache.get(object);_x000D_
_x000D_
        const result = object instanceof Array ? [] : {};_x000D_
_x000D_
        cache.set(object, result); // store reference to object before the recursive starts_x000D_
_x000D_
        if (object instanceof Array) {_x000D_
            for(const o of object) {_x000D_
                 result.push(copy(o));_x000D_
            }_x000D_
            return result;_x000D_
        }_x000D_
_x000D_
        const keys = Object.keys(object); _x000D_
_x000D_
        for (const key of keys)_x000D_
            result[key] = copy(object[key]);_x000D_
_x000D_
        return result;_x000D_
    }_x000D_
_x000D_
    return copy(obj);_x000D_
}_x000D_
_x000D_
function T(obj){_x000D_
    var clonedObjectsArray = [];_x000D_
    var originalObjectsArray = []; //used to remove the unique ids when finished_x000D_
    var next_objid = 0;_x000D_
_x000D_
    function objectId(obj) {_x000D_
        if (obj == null) return null;_x000D_
        if (obj.__obj_id == undefined){_x000D_
            obj.__obj_id = next_objid++;_x000D_
            originalObjectsArray[obj.__obj_id] = obj;_x000D_
        }_x000D_
        return obj.__obj_id;_x000D_
    }_x000D_
_x000D_
    function cloneRecursive(obj) {_x000D_
        if (null == obj || typeof obj == "string" || typeof obj == "number" || typeof obj == "boolean") return obj;_x000D_
_x000D_
        // Handle Date_x000D_
        if (obj instanceof Date) {_x000D_
            var copy = new Date();_x000D_
            copy.setTime(obj.getTime());_x000D_
            return copy;_x000D_
        }_x000D_
_x000D_
        // Handle Array_x000D_
        if (obj instanceof Array) {_x000D_
            var copy = [];_x000D_
            for (var i = 0; i < obj.length; ++i) {_x000D_
                copy[i] = cloneRecursive(obj[i]);_x000D_
            }_x000D_
            return copy;_x000D_
        }_x000D_
_x000D_
        // Handle Object_x000D_
        if (obj instanceof Object) {_x000D_
            if (clonedObjectsArray[objectId(obj)] != undefined)_x000D_
                return clonedObjectsArray[objectId(obj)];_x000D_
_x000D_
            var copy;_x000D_
            if (obj instanceof Function)//Handle Function_x000D_
                copy = function(){return obj.apply(this, arguments);};_x000D_
            else_x000D_
                copy = {};_x000D_
_x000D_
            clonedObjectsArray[objectId(obj)] = copy;_x000D_
_x000D_
            for (var attr in obj)_x000D_
                if (attr != "__obj_id" && obj.hasOwnProperty(attr))_x000D_
                    copy[attr] = cloneRecursive(obj[attr]);                 _x000D_
_x000D_
            return copy;_x000D_
        }       _x000D_
_x000D_
_x000D_
        throw new Error("Unable to copy obj! Its type isn't supported.");_x000D_
    }_x000D_
    var cloneObj = cloneRecursive(obj);_x000D_
_x000D_
_x000D_
_x000D_
    //remove the unique ids_x000D_
    for (var i = 0; i < originalObjectsArray.length; i++)_x000D_
    {_x000D_
        delete originalObjectsArray[i].__obj_id;_x000D_
    };_x000D_
_x000D_
    return cloneObj;_x000D_
}_x000D_
_x000D_
function U(obj) {_x000D_
  /*_x000D_
    Deep copy objects by value rather than by reference,_x000D_
    exception: `Proxy`_x000D_
  */_x000D_
_x000D_
  const seen = new WeakMap()_x000D_
_x000D_
  return clone(obj)_x000D_
_x000D_
  function defineProp(object, key, descriptor = {}, copyFrom = {}) {_x000D_
    const { configurable: _configurable, writable: _writable }_x000D_
      = Object.getOwnPropertyDescriptor(object, key)_x000D_
      || { configurable: true, writable: true }_x000D_
_x000D_
    const test = _configurable // Can redefine property_x000D_
      && (_writable === undefined || _writable) // Can assign to property_x000D_
_x000D_
    if (!test || arguments.length <= 2) return test_x000D_
_x000D_
    const basisDesc = Object.getOwnPropertyDescriptor(copyFrom, key)_x000D_
      || { configurable: true, writable: true } // Custom…_x000D_
      || {}; // …or left to native default settings_x000D_
_x000D_
    ["get", "set", "value", "writable", "enumerable", "configurable"]_x000D_
      .forEach(attr =>_x000D_
        descriptor[attr] === undefined &&_x000D_
        (descriptor[attr] = basisDesc[attr])_x000D_
      )_x000D_
_x000D_
    const { get, set, value, writable, enumerable, configurable }_x000D_
      = descriptor_x000D_
_x000D_
    return Object.defineProperty(object, key, {_x000D_
      enumerable, configurable, ...get || set_x000D_
        ? { get, set } // Accessor descriptor_x000D_
        : { value, writable } // Data descriptor_x000D_
    })_x000D_
  }_x000D_
_x000D_
  function clone(object) {_x000D_
    if (object !== Object(object)) return object /*_x000D_
    —— Check if the object belongs to a primitive data type */_x000D_
_x000D_
    if (object instanceof Node) return object.cloneNode(true) /*_x000D_
    —— Clone DOM trees */_x000D_
_x000D_
    let _object // The clone of object_x000D_
_x000D_
    switch (object.constructor) {_x000D_
      case Array:_x000D_
      case Object:_x000D_
        _object = cloneObject(object)_x000D_
        break_x000D_
_x000D_
      case Date:_x000D_
        _object = new Date(+object)_x000D_
        break_x000D_
_x000D_
      case Function:_x000D_
        const fnStr = String(object)_x000D_
_x000D_
        _object = new Function("return " +_x000D_
          (/^(?!function |[^{]+?=>)[^(]+?\(/.test(fnStr)_x000D_
            ? "function " : ""_x000D_
          ) + fnStr_x000D_
        )()_x000D_
_x000D_
        copyPropDescs(_object, object)_x000D_
        break_x000D_
_x000D_
      case RegExp:_x000D_
        _object = new RegExp(object)_x000D_
        break_x000D_
_x000D_
      default:_x000D_
        switch (Object.prototype.toString.call(object.constructor)) {_x000D_
          //                              // Stem from:_x000D_
          case "[object Function]":       // `class`_x000D_
          case "[object Undefined]":      // `Object.create(null)`_x000D_
            _object = cloneObject(object)_x000D_
            break_x000D_
_x000D_
          default:                        // `Proxy`_x000D_
            _object = object_x000D_
        }_x000D_
    }_x000D_
_x000D_
    return _object_x000D_
  }_x000D_
_x000D_
_x000D_
  function cloneObject(object) {_x000D_
    if (seen.has(object)) return seen.get(object) /*_x000D_
    —— Handle recursive references (circular structures) */_x000D_
_x000D_
    const _object = Array.isArray(object)_x000D_
      ? []_x000D_
      : Object.create(Object.getPrototypeOf(object)) /*_x000D_
        —— Assign [[Prototype]] for inheritance */_x000D_
_x000D_
    seen.set(object, _object) /*_x000D_
    —— Make `_object` the associative mirror of `object` */_x000D_
_x000D_
    Reflect.ownKeys(object).forEach(key =>_x000D_
      defineProp(_object, key, { value: clone(object[key]) }, object)_x000D_
    )_x000D_
_x000D_
    return _object_x000D_
  }_x000D_
_x000D_
_x000D_
  function copyPropDescs(target, source) {_x000D_
    Object.defineProperties(target,_x000D_
      Object.getOwnPropertyDescriptors(source)_x000D_
    )_x000D_
  }_x000D_
}_x000D_
 _x000D_
// ------------------------_x000D_
// Test properties_x000D_
// ------------------------_x000D_
_x000D_
_x000D_
console.log(`  shallow deep  func  circ  undefined date  RegExp bigInt`)_x000D_
_x000D_
log(A);_x000D_
log(B);_x000D_
log(C);_x000D_
log(D);_x000D_
log(E);_x000D_
log(F);_x000D_
log(G);_x000D_
log(H);_x000D_
log(I);_x000D_
log(J);_x000D_
log(K);_x000D_
log(L);_x000D_
log(M);_x000D_
log(N);_x000D_
log(O);_x000D_
log(P);_x000D_
log(Q);_x000D_
log(R);_x000D_
log(S);_x000D_
log(T);_x000D_
log(U);_x000D_
_x000D_
console.log(`  shallow deep  func  circ  undefined date  RegExp bigInt_x000D_
----_x000D_
LEGEND:_x000D_
shallow - solution create shallow copy_x000D_
deep - solution create deep copy_x000D_
func - solution copy functions_x000D_
circ - solution can copy object with circular references_x000D_
undefined - solution copy fields with undefined value_x000D_
date - solution can copy date_x000D_
RegExp - solution can copy fields with regular expressions_x000D_
bigInt - solution can copy BigInt_x000D_
`)_x000D_
_x000D_
_x000D_
// ------------------------_x000D_
// Helper functions_x000D_
// ------------------------_x000D_
_x000D_
_x000D_
function deepCompare(obj1,obj2) {_x000D_
  return JSON.stringify(obj1)===JSON.stringify(obj2);_x000D_
}_x000D_
_x000D_
function getCase() { // pure data case_x000D_
  return { _x000D_
    undef: undefined,_x000D_
    bool: true, num: 1, str: "txt1",    _x000D_
    e1: null, e2: [], e3: {}, e4: 0, e5: false,_x000D_
    arr: [ false, 2, "txt3", null, [], {},_x000D_
      [ true,4,"txt5",null, [], {},  [true,6,"txt7",null,[],{} ], _x000D_
        {bool: true,num: 8, str: "txt9", e1:null, e2:[] ,e3:{} ,e4: 0, e5: false}_x000D_
      ],_x000D_
        {bool: true,num: 10, str: "txt11", e1:null, e2:[] ,e3:{} ,e4: 0, e5: false}_x000D_
    ], _x000D_
    obj: { _x000D_
        bool: true, num: 12, str: "txt13",_x000D_
        e1: null, e2: [], e3: {}, e4: 0, e5: false,_x000D_
        arr: [true,14,"txt15",null,[],{} ],_x000D_
        obj: { _x000D_
          bool: true, num: 16, str: "txt17",_x000D_
          e1: null, e2: [], e3: {}, e4: 0, e5: false,_x000D_
          arr: [true,18,"txt19",null,[],{} ],_x000D_
          obj: {bool: true,num: 20, str: "txt21", e1:null, e2:[] ,e3:{} ,e4: 0, e5: false}_x000D_
      } _x000D_
    } _x000D_
  };_x000D_
}_x000D_
_x000D_
function check(org, copy, field, newValue) {_x000D_
  copy[field] = newValue;_x000D_
  return deepCompare(org,copy); _x000D_
}_x000D_
_x000D_
function testFunc(f) {_x000D_
 let o = { a:1, fun: (i,j)=> i+j };_x000D_
  let c = f(o);_x000D_
  _x000D_
  let val = false_x000D_
  try{_x000D_
    val = c.fun(3,4)==7;_x000D_
  } catch(e) { }_x000D_
  return val;_x000D_
} _x000D_
_x000D_
function testCirc(f) {_x000D_
 function Circ() {_x000D_
    this.me = this;_x000D_
  }_x000D_
_x000D_
  var o = {_x000D_
      x: 'a',_x000D_
      circ: new Circ(),_x000D_
      obj_circ: null,_x000D_
  };_x000D_
  _x000D_
  o.obj_circ = o;_x000D_
_x000D_
  let val = false;_x000D_
_x000D_
  try{_x000D_
    let c = f(o);  _x000D_
    val = (o.obj_circ == o) && (o.circ == o.circ.me);_x000D_
  } catch(e) { }_x000D_
  return val;_x000D_
} _x000D_
_x000D_
function testRegExp(f) {_x000D_
  let o = {_x000D_
    re: /a[0-9]+/,_x000D_
  };_x000D_
  _x000D_
  let val = false;_x000D_
_x000D_
  try{_x000D_
    let c = f(o);  _x000D_
    val = (String(c.re) == String(/a[0-9]+/));_x000D_
  } catch(e) { }_x000D_
  return val;_x000D_
}_x000D_
_x000D_
function testDate(f) {_x000D_
  let o = {_x000D_
    date: new Date(),_x000D_
  };_x000D_
  _x000D_
  let val = false;_x000D_
_x000D_
  try{_x000D_
    let c = f(o);  _x000D_
    val = (+new Date(c.date) == +new Date(o.date));_x000D_
  } catch(e) { }_x000D_
  return val;_x000D_
}_x000D_
_x000D_
function testBigInt(f) {_x000D_
  let val = false;_x000D_
  _x000D_
  try{_x000D_
    let o = {_x000D_
      big: 123n,_x000D_
    };_x000D_
  _x000D_
    let c = f(o);  _x000D_
  _x000D_
    val = o.big == c.big;_x000D_
  } catch(e) { }_x000D_
  _x000D_
  return val;_x000D_
}_x000D_
_x000D_
function log(f) {_x000D_
  let o = getCase();  // orginal object_x000D_
  let oB = getCase(); // "backup" used for shallow valid test_x000D_
  _x000D_
  let c1 = f(o); // copy 1 for reference_x000D_
  let c2 = f(o); // copy 2 for test shallow values_x000D_
  let c3 = f(o); // copy 3 for test deep values_x000D_
_x000D_
  let is_proper_copy = deepCompare(c1,o);  // shoud be true_x000D_
  _x000D_
  // shallow changes_x000D_
  let testShallow = _x000D_
    [ ['bool',false],['num',666],['str','xyz'],['arr',[]],['obj',{}] ]_x000D_
    .reduce((acc,curr)=> acc && check(c1,c2,curr[0], curr[1]), true );_x000D_
  _x000D_
  // should be true (original object shoud not have changed shallow fields)_x000D_
  let is_valid = deepCompare(o,oB); _x000D_
_x000D_
  // deep test (intruduce some change)_x000D_
  if (c3.arr[6]) c3.arr[6][7].num = 777;_x000D_
  _x000D_
  let diff_shallow = !testShallow; // shoud be true (shallow field was copied)_x000D_
  let diff_deep = !deepCompare(c1,c3);    // shoud be true (deep field was copied)_x000D_
  let can_copy_functions = testFunc(f);_x000D_
  let can_copy_circular = testCirc(f);_x000D_
  let can_copy_regexp = testRegExp(f);_x000D_
  let can_copy_date = testDate(f);_x000D_
  let can_copy_bigInt = testBigInt(f);_x000D_
  _x000D_
  let has_undefined = 'undef' in c1; // field with undefined value is copied?  _x000D_
  let is_ok = is_valid && is_proper_copy;_x000D_
  let b=(bool) => (bool+'').padEnd(5,' '); // bool value to formated string_x000D_
  _x000D_
  testFunc(f);_x000D_
  _x000D_
  if(is_ok) {_x000D_
    console.log(`${f.name} ${b(diff_shallow)}   ${b(diff_deep)} ${b(can_copy_functions)} ${b(can_copy_circular)} ${b(has_undefined)}     ${b(can_copy_date)} ${b(can_copy_regexp)}  ${b(can_copy_bigInt)}`)_x000D_
  } else {_x000D_
    console.log(`${f.name}: INVALID ${is_valid} ${is_proper_copy}`,{c1})_x000D_
  }_x000D_
  _x000D_
}
_x000D_
<script src="https://code.jquery.com/jquery-3.5.0.min.js" integrity="sha256-xNzN2a4ltkB44Mc/Jz3pT4iU1cmeR0FkXs4pru/JxaQ=" crossorigin="anonymous"></script>_x000D_
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>_x000D_
_x000D_
This snippet only presents tested solutions and show differences between them (but it no make performence tests)
_x000D_
_x000D_
_x000D_

Below there are example results for Chrome for shallow-big object

enter image description here


The solution JSON.parse(JSON.stringify(orig_obj) as stated by many peers here for deep_cloning has several issues which I found, and they are listed below:

  1. It discards the entries while copying whose values are undefined in the original object,
  2. If there are some values like Infinity, NaN etc, they will be converted into null while copying,
  3. If there is a Date type in the original object, it will be stringified in the cloned object (typeof date_entry --> string).

Found an effective way for cloning an object, and it worked well for me in all sort of scenarios. Please have a look at below code, as it has resolved all above mentioned pitfalls of JSON.parse(...), yet resulting in proper deep-cloning:

var orig_obj = {
  string: 'my_str',
  number: 123,
  bool: false,
  nul: null,
  nested : {
    value : true
  },
  nan : NaN,
  date: new Date(), 
  undef: undefined,
  inf: Infinity,
}
console.log("original_obj before modification: ", orig_obj, "\n");
console.log(typeof orig_obj.date, "\n");

var clone_obj = Object.assign({}, orig_obj);

//this below loop will help in deep cloning and solving above issues
for(let prop in orig_obj) {
    if(typeof orig_obj[prop] === "object") {
        if(orig_obj[prop] instanceof Date)
            clone_obj[prop] = orig_obj[prop];
        else {
            clone_obj[prop] = JSON.parse(JSON.stringify(orig_obj[prop]));
        }
    }
}

console.log("cloned_obj before modification: ", orig_obj, "\n");

clone_obj.bool = true;
clone_obj.nested.value = "false";

console.log("original_obj post modification: ", orig_obj, "\n");
console.log("cloned_obj post modification: ", clone_obj, "\n");
console.log(typeof clone_obj.date);

I think, that recurrence with caching is the best what we can do it here without libraries.

And underestimated WeakMap comes to the problem of cycles, wherein storing pairs of references to old and new object can help us to recreate pretty easily whole tree.

I prevented deep cloning of the DOM elements, probably you don't want to clone entire page :)

function deepCopy(object) {
    const cache = new WeakMap(); // Map of old - new references

    function copy(obj) {
        if (typeof obj !== 'object' ||
            obj === null ||
            obj instanceof HTMLElement
        )
            return obj; // primitive value or HTMLElement

        if (obj instanceof Date) 
            return new Date().setTime(obj.getTime());

        if (obj instanceof RegExp) 
            return new RegExp(obj.source, obj.flags);

        if (cache.has(obj)) 
            return cache.get(obj);

        const result = obj instanceof Array ? [] : {};

        cache.set(obj, result); // store reference to object before the recursive starts

        if (obj instanceof Array) {
            for(const o of obj) {
                 result.push(copy(o));
            }
            return result;
        }

        const keys = Object.keys(obj); 

        for (const key of keys)
            result[key] = copy(obj[key]);

        return result;
    }

    return copy(object);
}

Some tests:

// #1
const obj1 = { };
const obj2 = { };
obj1.obj2 = obj2;
obj2.obj1 = obj1; // Trivial circular reference

var copy = deepCopy(obj1);
copy == obj1 // false
copy.obj2 === obj1.obj2 // false
copy.obj2.obj1.obj2 // and so on - no error (correctly cloned).

// #2
const obj = { x: 0 }
const clone = deepCopy({ a: obj, b: obj });
clone.a == clone.b // true

// #3
const arr = [];
arr[0] = arr; // A little bit weird but who cares
clone = deepCopy(arr)
clone == arr // false;
clone[0][0][0][0] == clone // true;

NOTE: I'm using constants, for of loop, => operator and WeakMaps to create more essential code. This syntax (ES6) is supported by today's browsers


Structured Cloning

The HTML standard includes an internal structured cloning/serialization algorithm that can create deep clones of objects. It is still limited to certain built-in types, but in addition to the few types supported by JSON it also supports Dates, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays, and probably more in the future. It also preserves references within the cloned data, allowing it to support cyclical and recursive structures that would cause errors for JSON.

Support in Node.js: Experimental

The v8 module in Node.js currently (as of Node 11) exposes the structured serialization API directly, but this functionality is still marked as "experimental", and subject to change or removal in future versions. If you're using a compatible version, cloning an object is as simple as:

const v8 = require('v8');

const structuredClone = obj => {
  return v8.deserialize(v8.serialize(obj));
};

Direct Support in Browsers: Maybe Eventually?

Browsers do not currently provide a direct interface for the structured cloning algorithm, but a global structuredClone() function has been discussed in whatwg/html#793 on GitHub. As currently proposed, using it for most purposes would be as simple as:

const clone = structuredClone(original);

Unless this is shipped, browsers' structured clone implementations are only exposed indirectly.

Asynchronous Workaround: Usable.

The lower-overhead way to create a structured clone with existing APIs is to post the data through one port of a MessageChannels. The other port will emit a message event with a structured clone of the attached .data. Unfortunately, listening for these events is necessarily asynchronous, and the synchronous alternatives are less practical.

class StructuredCloner {
  constructor() {
    this.pendingClones_ = new Map();
    this.nextKey_ = 0;

    const channel = new MessageChannel();
    this.inPort_ = channel.port1;
    this.outPort_ = channel.port2;

    this.outPort_.onmessage = ({data: {key, value}}) => {
      const resolve = this.pendingClones_.get(key);
      resolve(value);
      this.pendingClones_.delete(key);
    };
    this.outPort_.start();
  }

  cloneAsync(value) {
    return new Promise(resolve => {
      const key = this.nextKey_++;
      this.pendingClones_.set(key, resolve);
      this.inPort_.postMessage({key, value});
    });
  }
}

const structuredCloneAsync = window.structuredCloneAsync =
    StructuredCloner.prototype.cloneAsync.bind(new StructuredCloner);

Example Use:

const main = async () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = await structuredCloneAsync(original);

  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));

  console.log("Assertions complete.");
};

main();

Synchronous Workarounds: Awful!

There are no good options for creating structured clones synchronously. Here are a couple of impractical hacks instead.

history.pushState() and history.replaceState() both create a structured clone of their first argument, and assign that value to history.state. You can use this to create a structured clone of any object like this:

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

Example Use:

_x000D_
_x000D_
'use strict';_x000D_
_x000D_
const main = () => {_x000D_
  const original = { date: new Date(), number: Math.random() };_x000D_
  original.self = original;_x000D_
_x000D_
  const clone = structuredClone(original);_x000D_
  _x000D_
  // They're different objects:_x000D_
  console.assert(original !== clone);_x000D_
  console.assert(original.date !== clone.date);_x000D_
_x000D_
  // They're cyclical:_x000D_
  console.assert(original.self === original);_x000D_
  console.assert(clone.self === clone);_x000D_
_x000D_
  // They contain equivalent values:_x000D_
  console.assert(original.number === clone.number);_x000D_
  console.assert(Number(original.date) === Number(clone.date));_x000D_
  _x000D_
  console.log("Assertions complete.");_x000D_
};_x000D_
_x000D_
const structuredClone = obj => {_x000D_
  const oldState = history.state;_x000D_
  history.replaceState(obj, null);_x000D_
  const clonedObj = history.state;_x000D_
  history.replaceState(oldState, null);_x000D_
  return clonedObj;_x000D_
};_x000D_
_x000D_
main();
_x000D_
_x000D_
_x000D_

Though synchronous, this can be extremely slow. It incurs all of the overhead associated with manipulating the browser history. Calling this method repeatedly can cause Chrome to become temporarily unresponsive.

The Notification constructor creates a structured clone of its associated data. It also attempts to display a browser notification to the user, but this will silently fail unless you have requested notification permission. In case you have the permission for other purposes, we'll immediately close the notification we've created.

const structuredClone = obj => {
  const n = new Notification('', {data: obj, silent: true});
  n.onshow = n.close.bind(n);
  return n.data;
};

Example Use:

_x000D_
_x000D_
'use strict';_x000D_
_x000D_
const main = () => {_x000D_
  const original = { date: new Date(), number: Math.random() };_x000D_
  original.self = original;_x000D_
_x000D_
  const clone = structuredClone(original);_x000D_
  _x000D_
  // They're different objects:_x000D_
  console.assert(original !== clone);_x000D_
  console.assert(original.date !== clone.date);_x000D_
_x000D_
  // They're cyclical:_x000D_
  console.assert(original.self === original);_x000D_
  console.assert(clone.self === clone);_x000D_
_x000D_
  // They contain equivalent values:_x000D_
  console.assert(original.number === clone.number);_x000D_
  console.assert(Number(original.date) === Number(clone.date));_x000D_
  _x000D_
  console.log("Assertions complete.");_x000D_
};_x000D_
_x000D_
const structuredClone = obj => {_x000D_
  const n = new Notification('', {data: obj, silent: true});_x000D_
  n.close();_x000D_
  return n.data;_x000D_
};_x000D_
_x000D_
main();
_x000D_
_x000D_
_x000D_


//
// creates 'clone' method on context object
//
//  var 
//     clon = Object.clone( anyValue );
//
!((function (propertyName, definition) {
    this[propertyName] = definition();
}).call(
    Object,
    "clone",
    function () {
        function isfn(fn) {
            return typeof fn === "function";
        }

        function isobj(o) {
            return o === Object(o);
        }

        function isarray(o) {
            return Object.prototype.toString.call(o) === "[object Array]";
        }

        function fnclon(fn) {
            return function () {
                fn.apply(this, arguments);
            };
        }

        function owns(obj, p) {
            return obj.hasOwnProperty(p);
        }

        function isemptyobj(obj) {
            for (var p in obj) {
                return false;
            }
            return true;
        }

        function isObject(o) {
            return Object.prototype.toString.call(o) === "[object Object]";
        }
        return function (input) {
            if (isfn(input)) {
                return fnclon(input);
            } else if (isobj(input)) {
                var cloned = {};
                for (var p in input) {
                    owns(Object.prototype, p)
                    || (
                        isfn(input[p])
                        && ( cloned[p] = function () { return input[p].apply(input, arguments); } )
                        || ( cloned[p] = input[p] )
                    );
                }
                if (isarray(input)) {
                    cloned.length = input.length;
                    "concat every filter forEach indexOf join lastIndexOf map pop push reduce reduceRight reverse shift slice some sort splice toLocaleString toString unshift"
                    .split(" ")
                    .forEach(
                      function (methodName) {
                        isfn( Array.prototype[methodName] )
                        && (
                            cloned[methodName] =
                            function () {
                                return Array.prototype[methodName].apply(cloned, arguments);
                            }
                        );
                      }
                    );
                }
                return isemptyobj(cloned)
                       ? (
                          isObject(input)
                          ? cloned
                          : input
                        )
                       : cloned;
            } else {
                return input;
            }
        };
    }
));
//

In my code I frequently define a function (_) to handle copies so that I can pass by value to functions. This code creates a deep copy but maintains inheritance. It also keeps track of sub-copies so that self-referential objects can be copied without an infinite loop. Feel free to use it.

It might not be the most elegant, but it hasn't failed me yet.

_ = function(oReferance) {
  var aReferances = new Array();
  var getPrototypeOf = function(oObject) {
    if(typeof(Object.getPrototypeOf)!=="undefined") return Object.getPrototypeOf(oObject);
    var oTest = new Object();
    if(typeof(oObject.__proto__)!=="undefined"&&typeof(oTest.__proto__)!=="undefined"&&oTest.__proto__===Object.prototype) return oObject.__proto__;
    if(typeof(oObject.constructor)!=="undefined"&&typeof(oTest.constructor)!=="undefined"&&oTest.constructor===Object&&typeof(oObject.constructor.prototype)!=="undefined") return oObject.constructor.prototype;
    return Object.prototype;
  };
  var recursiveCopy = function(oSource) {
    if(typeof(oSource)!=="object") return oSource;
    if(oSource===null) return null;
    for(var i=0;i<aReferances.length;i++) if(aReferances[i][0]===oSource) return aReferances[i][1];
    var Copy = new Function();
    Copy.prototype = getPrototypeOf(oSource);
    var oCopy = new Copy();
    aReferances.push([oSource,oCopy]);
    for(sPropertyName in oSource) if(oSource.hasOwnProperty(sPropertyName)) oCopy[sPropertyName] = recursiveCopy(oSource[sPropertyName]);
    return oCopy;
  };
  return recursiveCopy(oReferance);
};

// Examples:
Wigit = function(){};
Wigit.prototype.bInThePrototype = true;
A = new Wigit();
A.nCoolNumber = 7;
B = _(A);
B.nCoolNumber = 8; // A.nCoolNumber is still 7
B.bInThePrototype // true
B instanceof Wigit // true

If you're okay with a shallow copy, the underscore.js library has a clone method.

y = _.clone(x);

or you can extend it like

copiedObject = _.extend({},originalObject);

OK, imagine you have this object below and you want to clone it:

let obj = {a:1, b:2, c:3}; //ES6

or

var obj = {a:1, b:2, c:3}; //ES5

the answer is mainly depeneds on which ECMAscript you using, in ES6+, you can simply use Object.assign to do the clone:

let cloned = Object.assign({}, obj); //new {a:1, b:2, c:3};

or using spread operator like this:

let cloned = {...obj}; //new {a:1, b:2, c:3};

But if you using ES5, you can use few methods, but the JSON.stringify, just make sure you not using for a big chunk of data to copy, but it could be one line handy way in many cases, something like this:

let cloned = JSON.parse(JSON.stringify(obj)); 
//new {a:1, b:2, c:3};, can be handy, but avoid using on big chunk of data over and over

Per MDN:

  • If you want shallow copy, use Object.assign({}, a)
  • For "deep" copy, use JSON.parse(JSON.stringify(a))

There is no need for external libraries but you need to check browser compatibility first.


I came to this page due to the same question but I'm neither using JQuery and none of the clone-Methods worked for my own objects.

I'm aware my answer isn't related too strong to this question because it's a different approach. Instead of using clone-functions I use a create function. It worked for me for the following (unfortunately restricting) purposes:

  1. I use mostly JSP-generated Javascript
  2. I know in the beginning which Object must be generated (In my case it's Information from a Database which gets fetched once and needs to be deployed more often in the JS.

First I defined my Objects like this:

var obj= new Object();
obj.Type='Row';
obj.ID=1;
obj.Value='Blah blah';

Now I moved everything like:

function getObjSelektor(id_nummer,selected){
var obj = document.createElement("select");
obj.setAttribute("id","Selektor_"+id_nummer);
obj.setAttribute("name","Selektor");
obj.setAttribute("size","1");

var obj_opt_1 = document.createElement("option");
obj_opt_1.setAttribute("value","1");
if(1==selected)
    posopval_opt_1.setAttribute("selected","selected");
obj_opt_1.innerHTML="Blah blah";
obj.appendChild(obj_opt_1);

var obj_opt_2 = document.createElement("option");
obj_opt_2.setAttribute("value","2");
if(2==selected)
    obj_opt_2.setAttribute("selected","selected");
obj_opt_2.innerHTML="2nd Row";
obj.appendChild(obj_opt_2);

...

return obj;
}

And call the function in the regular code:

myDiv.getObjSelektor(getObjSelektor(anotherObject.ID));

As said this is a different approach which solved my issue for my purposes.


let clone = Object.assign( Object.create( Object.getPrototypeOf(obj)), obj)

ES6 solution if you want to (shallow) clone a class instance and not just a property object.


Ok, I know it has many answers, but no one pointed out, EcmaScript5 has assign method, work on FF and Chrome, it copies enumerable and own properties and Symbols.

Object Assign


function clone(src, deep) {

    var toString = Object.prototype.toString;
    if(!src && typeof src != "object"){
        //any non-object ( Boolean, String, Number ), null, undefined, NaN
        return src;
    }

    //Honor native/custom clone methods
    if(src.clone && toString.call(src.clone) == "[object Function]"){
        return src.clone(deep);
    }

    //DOM Elements
    if(src.nodeType && toString.call(src.cloneNode) == "[object Function]"){
        return src.cloneNode(deep);
    }

    //Date
    if(toString.call(src) == "[object Date]"){
        return new Date(src.getTime());
    }

    //RegExp
    if(toString.call(src) == "[object RegExp]"){
        return new RegExp(src);
    }

    //Function
    if(toString.call(src) == "[object Function]"){
        //Wrap in another method to make sure == is not true;
        //Note: Huge performance issue due to closures, comment this :)
        return (function(){
            src.apply(this, arguments);
        });

    }

    var ret, index;
    //Array
    if(toString.call(src) == "[object Array]"){
        //[].slice(0) would soft clone
        ret = src.slice();
        if(deep){
            index = ret.length;
            while(index--){
                ret[index] = clone(ret[index], true);
            }
        }
    }
    //Object
    else {
        ret = src.constructor ? new src.constructor() : {};
        for (var prop in src) {
            ret[prop] = deep
                ? clone(src[prop], true)
                : src[prop];
        }
    }

    return ret;
};

Since mindeavor stated that the object to be cloned is a 'literal-constructed' object, a solution might be to simply generate the object multiple times rather than cloning an instance of the object:

function createMyObject()
{
    var myObject =
    {
        ...
    };
    return myObject;
}

var myObjectInstance1 = createMyObject();
var myObjectInstance2 = createMyObject();

I don't know which cases this doesn't work for, but it got me a copy of an array. I think its cute :) Hope it helps

copiedArr = origArr.filter(function(x){return true})

In ECMAScript 2018

let objClone = { ...obj };

Be aware that nested objects are still copied as a reference.


Object copy using ( ... )

//bad
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2,c: 3 }

//good
const originalObj = { id: 5, name: 'San Francisco'};
const copyObject = {...originalObj, pincode: 4444};
console.log(copyObject)  //{ id: 5, name: 'San Francisco', pincode: 4444 }

Same can be use for copying array from one to other

const itemsCopy = [...items];

Just as this link says use this code:

let clone = Object.create(Object.getPrototypeOf(obj),
 Object.getOwnPropertyDescriptors(obj));

To handle circular objects that that JSON.stringify can't handle, you can bring in a library called JSOG, that serializes and deserializes arbitrary graphs into JSON format.

var clone = JSOG.parse(JSOG.stringify(original));

It might also be interesting to try patching JSOG for cloning with this trick (don't have time at the moment, but if someone wants to give it a shot...):

Serialize a simple function :

foo.f = function(a) { return a }
var stringForm = foo.f.toString() // "function (a) { return a }"

Deserialize a function :

eval("foo.f = " + stringForm)

Some conventions (probably in the name of the property) to identify functions vs regular strings would be needed (@func_f perhaps).

Of course if the function calls a second function the second function will need to exist just as it would for the original.

The above however is quite dangerous if you are to accept the serialized form from an untrusted source, but then accepting any function in any form from an untrusted source would be dangerous, so if you're interested in cloning functions trust must have already been established (or you're already intent on writing a security flaw!).

Disclaimer: I have not tested the speed of JSOG stringify/parse vs JSON stringify/parse, but It does work on the simple (circular) objects I tested it with.


You can use functional closure to gain all the benefits of a deep copy, without a deep copy. It's a very different paradigm, but works well. Instead of trying to copy an existing object, just use a function to instantiate a new object when you need one.

First, create an function that returns an object

function template() {
  return {
    values: [1, 2, 3],
    nest: {x: {a: "a", b: "b"}, y: 100}
  };
}

Then create a simple shallow copy function

function copy(a, b) {
  Object.keys(b).forEach(function(key) {
    a[key] = b[key];
  });
}

Create a new object, and copy the template's properties onto it

var newObject = {}; 
copy(newObject, template());

But the above copy step is not necessary. All you need to do is this:

var newObject = template();

Now that you have a new object, test to see what its properties are:

console.log(Object.keys(newObject));

This displays:

["values", "nest"]

Yes, those are the newObject's own properties, not references to properties on another object. Let's just check:

console.log(newObject.nest.x.b);

This displays:

"b"

The newObject has acquired all of the template object's properties, but is free of any dependency chain.

http://jsbin.com/ISUTIpoC/1/edit?js,console

I added this example to encourage some debate, so please add some comments :)


You may clone your Object without modification parent Object -

    /** [Object Extend]*/
    ( typeof Object.extend === 'function' ? undefined : ( Object.extend = function ( destination, source ) {
        for ( var property in source )
            destination[property] = source[property];
        return destination;
    } ) );
    /** [/Object Extend]*/
    /** [Object clone]*/
    ( typeof Object.clone === 'function' ? undefined : ( Object.clone = function ( object ) {
        return this.extend( {}, object );
    } ) );
    /** [/Object clone]*/

    let myObj = {
        a:1, b:2, c:3, d:{
            a:1, b:2, c:3
        }
    };

    let clone = Object.clone( myObj );

    clone.a = 10;

    console.log('clone.a==>', clone.a); //==> 10

    console.log('myObj.a==>', myObj.a); //==> 1 // object not modified here

    let clone2 = Object.clone( clone );

    clone2.a = 20;

    console.log('clone2.a==>', clone2.a); //==> 20

    console.log('clone.a==>', clone.a); //==> 10 // object not modified here

var x = {'e': 2, 'd': 8, 'b': 5};

const y = {};
for(let key in x) {
    y[key] = x[key];
}
console.log(y); // =>>> {e: 2, d: 8, b: 5}

const z = {};
Object.keys(x).forEach(key => {
    z[key] = x[key];
});
console.log(z); // =>>> {e: 2, d: 8, b: 5}

const w = {};
for(let i = 0; i < Object.keys(x).length; i++) {
    w[Object.keys(x)[i]] = x[Object.keys(x)[i]];
}
console.log(w); // =>>> {e: 2, d: 8, b: 5}

const v = {};
for(let key of Object.keys(x)) {
    v[key] = x[key];
}
console.log(v); // =>>> {e: 2, d: 8, b: 5}

x['q'] = 100;   // Altering x will not affect the other objects

console.log(x); // =>>> {e: 2, d: 8, b: 5, q: 100}
console.log(y); // =>>> {e: 2, d: 8, b: 5}
console.log(z); // =>>> {e: 2, d: 8, b: 5}
console.log(w); // =>>> {e: 2, d: 8, b: 5}
console.log(v); // =>>> {e: 2, d: 8, b: 5}

New answer to an old question! If you have the pleasure of having using ECMAScript 2016 (ES6) with Spread Syntax, it's easy.

keepMeTheSame = {first: "Me!", second: "You!"};
cloned = {...keepMeTheSame}

This provides a clean method for a shallow copy of an object. Making a deep copy, meaning makign a new copy of every value in every recursively nested object, requires on of the heavier solutions above.

JavaScript keeps evolving.


If you do not use Dates, functions, undefined, regExp or Infinity within your object, a very simple one liner is JSON.parse(JSON.stringify(object)):

_x000D_
_x000D_
const a = {_x000D_
  string: 'string',_x000D_
  number: 123,_x000D_
  bool: false,_x000D_
  nul: null,_x000D_
  date: new Date(),  // stringified_x000D_
  undef: undefined,  // lost_x000D_
  inf: Infinity,  // forced to 'null'_x000D_
}_x000D_
console.log(a);_x000D_
console.log(typeof a.date);  // Date object_x000D_
const clone = JSON.parse(JSON.stringify(a));_x000D_
console.log(clone);_x000D_
console.log(typeof clone.date);  // result of .toISOString()
_x000D_
_x000D_
_x000D_

This works for all kind of objects containing objects, arrays, strings, booleans and numbers.

See also this article about the structured clone algorithm of browsers which is used when posting messages to and from a worker. It also contains a function for deep cloning.


I've written my own implementation. Not sure if it counts as a better solution:

/*
    a function for deep cloning objects that contains other nested objects and circular structures.
    objects are stored in a 3D array, according to their length (number of properties) and their depth in the original object.
                                    index (z)
                                         |
                                         |
                                         |
                                         |
                                         |
                                         |                      depth (x)
                                         |_ _ _ _ _ _ _ _ _ _ _ _
                                        /_/_/_/_/_/_/_/_/_/
                                       /_/_/_/_/_/_/_/_/_/
                                      /_/_/_/_/_/_/...../
                                     /................./
                                    /.....            /
                                   /                 /
                                  /------------------
            object length (y)    /
*/

Following is the implementation:

function deepClone(obj) {
    var depth = -1;
    var arr = [];
    return clone(obj, arr, depth);
}

/**
 *
 * @param obj source object
 * @param arr 3D array to store the references to objects
 * @param depth depth of the current object relative to the passed 'obj'
 * @returns {*}
 */
function clone(obj, arr, depth){
    if (typeof obj !== "object") {
        return obj;
    }

    var length = Object.keys(obj).length; // native method to get the number of properties in 'obj'

    var result = Object.create(Object.getPrototypeOf(obj)); // inherit the prototype of the original object
    if(result instanceof Array){
        result.length = length;
    }

    depth++; // depth is increased because we entered an object here

    arr[depth] = []; // this is the x-axis, each index here is the depth
    arr[depth][length] = []; // this is the y-axis, each index is the length of the object (aka number of props)
    // start the depth at current and go down, cyclic structures won't form on depths more than the current one
    for(var x = depth; x >= 0; x--){
        // loop only if the array at this depth and length already have elements
        if(arr[x][length]){
            for(var index = 0; index < arr[x][length].length; index++){
                if(obj === arr[x][length][index]){
                    return obj;
                }
            }
        }
    }

    arr[depth][length].push(obj); // store the object in the array at the current depth and length
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) result[prop] = clone(obj[prop], arr, depth);
    }

    return result;
}

A.Levy's answer is almost complete, here is my little contribution: there is a way how to handle recursive references, see this line

if(this[attr]==this) copy[attr] = copy;

If the object is XML DOM element, we must use cloneNode instead

if(this.cloneNode) return this.cloneNode(true);

Inspired by A.Levy's exhaustive study and Calvin's prototyping approach, I offer this solution:

Object.prototype.clone = function() {
  if(this.cloneNode) return this.cloneNode(true);
  var copy = this instanceof Array ? [] : {};
  for(var attr in this) {
    if(typeof this[attr] == "function" || this[attr]==null || !this[attr].clone)
      copy[attr] = this[attr];
    else if(this[attr]==this) copy[attr] = copy;
    else copy[attr] = this[attr].clone();
  }
  return copy;
}

Date.prototype.clone = function() {
  var copy = new Date();
  copy.setTime(this.getTime());
  return copy;
}

Number.prototype.clone = 
Boolean.prototype.clone =
String.prototype.clone = function() {
  return this;
}

See also Andy Burke's note in the answers.


To support a better understanding of copying of objects, this illustrative jsbin may be of value

class base {
  get under(){return true}
}

class a extends base {}

const b = {
  get b1(){return true},
  b: true
}

console.log('Object assign')
let t1 = Object.create(b)
t1.x = true
const c = Object.assign(t1, new a())
console.log(c.b1 ? 'prop value copied': 'prop value gone')
console.log(c.x ? 'assigned value copied': 'assigned value gone')
console.log(c.under ? 'inheritance ok': 'inheritance gone')
console.log(c.b1 ? 'get value unchanged' : 'get value lost')
c.b1 = false
console.log(c.b1? 'get unchanged' : 'get lost')
console.log('-----------------------------------')
console.log('Object assign  - order swopped')
t1 = Object.create(b)
t1.x = true
const d = Object.assign(new a(), t1)
console.log(d.b1 ? 'prop value copied': 'prop value gone')
console.log(d.x ? 'assigned value copied': 'assigned value gone')
console.log(d.under ? 'inheritance n/a': 'inheritance gone')
console.log(d.b1 ? 'get value copied' : 'get value lost')
d.b1 = false
console.log(d.b1? 'get copied' : 'get lost')
console.log('-----------------------------------')
console.log('Spread operator')
t1 = Object.create(b)
t2 = new a()
t1.x = true
const e = { ...t1, ...t2 }
console.log(e.b1 ? 'prop value copied': 'prop value gone')
console.log(e.x ? 'assigned value copied': 'assigned value gone')
console.log(e.under ? 'inheritance ok': 'inheritance gone')
console.log(e.b1 ? 'get value copied' : 'get value lost')
e.b1 = false
console.log(e.b1? 'get copied' : 'get lost')
console.log('-----------------------------------')
console.log('Spread operator on getPrototypeOf')
t1 = Object.create(b)
t2 = new a()
t1.x = true
const e1 = { ...Object.getPrototypeOf(t1), ...Object.getPrototypeOf(t2) }
console.log(e1.b1 ? 'prop value copied': 'prop value gone')
console.log(e1.x ? 'assigned value copied': 'assigned value gone')
console.log(e1.under ? 'inheritance ok': 'inheritance gone')
console.log(e1.b1 ? 'get value copied' : 'get value lost')
e1.b1 = false
console.log(e1.b1? 'get copied' : 'get lost')
console.log('-----------------------------------')
console.log('keys, defineProperty, getOwnPropertyDescriptor')
f = Object.create(b)
t2 = new a()
f.x = 'a'
Object.keys(t2).forEach(key=> {
  Object.defineProperty(f,key,Object.getOwnPropertyDescriptor(t2, key))
})
console.log(f.b1 ? 'prop value copied': 'prop value gone')
console.log(f.x ? 'assigned value copied': 'assigned value gone')
console.log(f.under ? 'inheritance ok': 'inheritance gone')
console.log(f.b1 ? 'get value copied' : 'get value lost')
f.b1 = false
console.log(f.b1? 'get copied' : 'get lost')
console.log('-----------------------------------')
console.log('defineProperties, getOwnPropertyDescriptors')
let g = Object.create(b)
t2 = new a()
g.x = 'a'
Object.defineProperties(g,Object.getOwnPropertyDescriptors(t2))
console.log(g.b1 ? 'prop value copied': 'prop value gone')
console.log(g.x ? 'assigned value copied': 'assigned value gone')
console.log(g.under ? 'inheritance ok': 'inheritance gone')
console.log(g.b1 ? 'get value copied' : 'get value lost')
g.b1 = false
console.log(g.b1? 'get copied' : 'get lost')
console.log('-----------------------------------')

Use lodash _.cloneDeep().

Shallow Copy: lodash _.clone()

A shallow copy can be made by simply copying the reference.

let obj1 = {
    a: 0,
    b: {
        c: 0,
        e: {
            f: 0
        }
    }
};
let obj3 = _.clone(obj1);
obj1.a = 4;
obj1.b.c = 4;
obj1.b.e.f = 100;

console.log(JSON.stringify(obj1));
//{"a":4,"b":{"c":4,"e":{"f":100}}}

console.log(JSON.stringify(obj3));
//{"a":0,"b":{"c":4,"e":{"f":100}}}

Shallow Copy: lodash _.clone()

Deep Copy: lodash _.cloneDeep()

fields are dereferenced: rather than references to objects being copied

let obj1 = {
    a: 0,
    b: {
        c: 0,
        e: {
            f: 0
        }
    }
};
let obj3 = _.cloneDeep(obj1);
obj1.a = 100;
obj1.b.c = 100;
obj1.b.e.f = 100;

console.log(JSON.stringify(obj1));
{"a":100,"b":{"c":100,"e":{"f":100}}}

console.log(JSON.stringify(obj3));
{"a":0,"b":{"c":0,"e":{"f":0}}}

Deep Copy: lodash _.cloneDeep()


You can simply use a spread property to copy an object without references. But be careful (see comments), the 'copy' is just on the lowest object/array level. Nested properties are still references!


Complete clone:

let x = {a: 'value1'}
let x2 = {...x}

// => mutate without references:

x2.a = 'value2'
console.log(x.a)    // => 'value1'

Clone with references on second level:

const y = {a: {b: 'value3'}}
const y2 = {...y}

// => nested object is still a references:

y2.a.b = 'value4'
console.log(y.a.b)    // => 'value4'

JavaScript actually does not support deep clones natively. Use an utility function. For example Ramda:

http://ramdajs.com/docs/#clone


Simple recursive method to clone an object. Also could use lodash.clone.

_x000D_
_x000D_
let clone = (obj) => {_x000D_
 let obj2 = Array.isArray(obj) ? [] : {};_x000D_
 for(let k in obj) {_x000D_
          obj2[k] = (typeof obj[k] === 'object' ) ? clone(obj[k]) :  obj[k];_x000D_
        }_x000D_
        return obj2;_x000D_
    }_x000D_
_x000D_
let w = { name: "Apple", types: ["Fuji", "Gala"]};_x000D_
let x = clone(w);_x000D_
w.name = "Orange";_x000D_
w.types = ["Navel"];_x000D_
console.log(x);_x000D_
console.log(w);
_x000D_
_x000D_
_x000D_


If you are using TypeScript, need to support older web browsers (and so can't use Object.assign), and aren't using a library with a clone method build in, you can make yourself a combine helper in a few lines of code. It combines objects, and if you have only one, just clones it.

/** Creates a new object that combines the properties of the specified objects. */
function combine(...objs: {}[]) {
    const combined = {};
    objs.forEach(o => Object.keys(o).forEach(p => combined[p] = o[p]));
    return combined;
}

I think there is a simple and working answer. In deep copying there are two concerns:

  1. Keep properties independent to each other.
  2. And keep the methods alive on cloned object.

So I think one simple solution will be to first serialize and deserialize and then do an assign on it to copy functions too.

let deepCloned = JSON.parse(JSON.stringify(source));
let merged = Object.assign({}, source);
Object.assign(merged, deepCloned);

Although this question has many answers, I hope this one helps too.


The problem with copying an object that, eventually, may point at itself, can be solved with a simple check. Add this check, every time there is a copy action. It may be slow, but it should work.

I use a toType() function to return the object type, explicitly. I also have my own copyObj() function, which is rather similar in logic, which answers all three Object(), Array(), and Date() cases.

I run it in NodeJS.

NOT TESTED, YET.

// Returns true, if one of the parent's children is the target.
// This is useful, for avoiding copyObj() through an infinite loop!
function isChild(target, parent) {
  if (toType(parent) == '[object Object]') {
    for (var name in parent) {
      var curProperty = parent[name];

      // Direct child.
      if (curProperty = target) return true;

      // Check if target is a child of this property, and so on, recursively.
      if (toType(curProperty) == '[object Object]' || toType(curProperty) == '[object Array]') {
        if (isChild(target, curProperty)) return true;
      }
    }
  } else if (toType(parent) == '[object Array]') {
    for (var i=0; i < parent.length; i++) {
      var curItem = parent[i];

      // Direct child.
      if (curItem = target) return true;

      // Check if target is a child of this property, and so on, recursively.
      if (toType(curItem) == '[object Object]' || toType(curItem) == '[object Array]') {
        if (isChild(target, curItem)) return true;
      }
    }
  }

  return false;     // Not the target.
}

Using defaults (historically specific to nodejs but now usable from the browser thanks to modern JS):

import defaults from 'object.defaults';

const myCopy = defaults({}, myObject);

Clone an object based on a template. What do you do if you don't want an exact copy, but you do want the robustness of some kind of reliable clone operation but you only want bits cloned or you want to make sure you can control the existence or format of each attribute value cloned?

I am contributing this because it's useful for us and we created it because we could not find something similar. You can use it to clone an object based on a template object which specifies what attributes of the object I want to clone, and the template allows for functions to transform those attributes into something different if they don't exist on the source object or however you want to handle the clone. If it's not useful I am sure someone can delete this answer.

   function isFunction(functionToCheck) {
       var getType = {};
       return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
   }

   function cloneObjectByTemplate(obj, tpl, cloneConstructor) {
       if (typeof cloneConstructor === "undefined") {
           cloneConstructor = false;
       }
       if (obj == null || typeof (obj) != 'object') return obj;

       //if we have an array, work through it's contents and apply the template to each item...
       if (Array.isArray(obj)) {
           var ret = [];
           for (var i = 0; i < obj.length; i++) {
               ret.push(cloneObjectByTemplate(obj[i], tpl, cloneConstructor));
           }
           return ret;
       }

       //otherwise we have an object...
       //var temp:any = {}; // obj.constructor(); // we can't call obj.constructor because typescript defines this, so if we are dealing with a typescript object it might reset values.
       var temp = cloneConstructor ? new obj.constructor() : {};

       for (var key in tpl) {
           //if we are provided with a function to determine the value of this property, call it...
           if (isFunction(tpl[key])) {
               temp[key] = tpl[key](obj); //assign the result of the function call, passing in the value
           } else {
               //if our object has this property...
               if (obj[key] != undefined) {
                   if (Array.isArray(obj[key])) {
                       temp[key] = [];
                       for (var i = 0; i < obj[key].length; i++) {
                           temp[key].push(cloneObjectByTemplate(obj[key][i], tpl[key], cloneConstructor));
                       }
                   } else {
                       temp[key] = cloneObjectByTemplate(obj[key], tpl[key], cloneConstructor);
                   }
               }
           }
       }

       return temp;
   }

A simple way to call it would be like this:

var source = {
       a: "whatever",
       b: {
           x: "yeah",
           y: "haha"
       }
   };
   var template = {
       a: true, //we want to clone "a"
       b: {
           x: true //we want to clone "b.x" too
       }
   }; 
   var destination = cloneObjectByTemplate(source, template);

If you wanted to use a function to make sure an attribute is returned or to make sure it's a particular type, use a template like this. Instead of using { ID: true } we are providing a function which still just copies the ID attribute of the source object but it makes sure that it's a number even if it does not exist on the source object.

 var template = {
    ID: function (srcObj) {
        if(srcObj.ID == undefined){ return -1; }
        return parseInt(srcObj.ID.toString());
    }
}

Arrays will clone fine but if you want to you can have your own function handle those individual attributes too, and do something special like this:

 var template = {
    tags: function (srcObj) {
        var tags = [];
        if (process.tags != undefined) {
            for (var i = 0; i < process.tags.length; i++) {

                tags.push(cloneObjectByTemplate(
                  srcObj.tags[i],
                  { a : true, b : true } //another template for each item in the array
                );
            }
        }
        return tags;
    }
 }

So in the above, our template just copies the tags attribute of the source object if it exists, (it's assumed to be an array), and for each element in that array the clone function is called to individually clone it based on a second template which just copies the a and b attributes of each of those tag elements.

If you are taking objects in and out of node and you want to control which attributes of those objects are cloned then this is a great way of controlling that in node.js and the code works in the browser too.

Here is an example of it's use: http://jsfiddle.net/hjchyLt1/


There are several issues with most solutions on the internet. So I decided to make a follow-up, which includes, why the accepted answer shouldn't be accepted.

starting situation

I want to deep-copy a Javascript Object with all of its children and their children and so on. But since I'm not kind of a normal developer, my Object has normal properties, circular structures and even nested objects.

So let's create a circular structure and a nested object first.

function Circ() {
    this.me = this;
}

function Nested(y) {
    this.y = y;
}

Let's bring everything together in an Object named a.

var a = {
    x: 'a',
    circ: new Circ(),
    nested: new Nested('a')
};

Next, we want to copy a into a variable named b and mutate it.

var b = a;

b.x = 'b';
b.nested.y = 'b';

You know what happened here because if not you wouldn't even land on this great question.

console.log(a, b);

a --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

Now let's find a solution.

JSON

The first attempt I tried was using JSON.

var b = JSON.parse( JSON.stringify( a ) );

b.x = 'b';
b.nested.y = 'b';

Don't waste too much time on it, you'll get TypeError: Converting circular structure to JSON.

Recursive copy (the accepted "answer")

Let's have a look at the accepted answer.

function cloneSO(obj) {
    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = cloneSO(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        var copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

Looks good, heh? It's a recursive copy of the object and handles other types as well, like Date, but that wasn't a requirement.

var b = cloneSO(a);

b.x = 'b';
b.nested.y = 'b';

Recursion and circular structures doesn't work well together... RangeError: Maximum call stack size exceeded

native solution

After arguing with my co-worker, my boss asked us what happened, and he found a simple solution after some googling. It's called Object.create.

var b = Object.create(a);

b.x = 'b';
b.nested.y = 'b';

This solution was added to Javascript some time ago and even handles circular structure.

console.log(a, b);

a --> Object {
    x: "a",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

... and you see, it didn't work with the nested structure inside.

polyfill for the native solution

There's a polyfill for Object.create in the older browser just like the IE 8. It's something like recommended by Mozilla, and of course, it's not perfect and results in the same problem as the native solution.

function F() {};
function clonePF(o) {
    F.prototype = o;
    return new F();
}

var b = clonePF(a);

b.x = 'b';
b.nested.y = 'b';

I've put F outside the scope so we can have a look at what instanceof tells us.

console.log(a, b);

a --> Object {
    x: "a",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> F {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> true

Same problem as the native solution, but a little bit worse output.

the better (but not perfect) solution

When digging around, I found a similar question (In Javascript, when performing a deep copy, how do I avoid a cycle, due to a property being "this"?) to this one, but with a way better solution.

function cloneDR(o) {
    const gdcc = "__getDeepCircularCopy__";
    if (o !== Object(o)) {
        return o; // primitive value
    }

    var set = gdcc in o,
        cache = o[gdcc],
        result;
    if (set && typeof cache == "function") {
        return cache();
    }
    // else
    o[gdcc] = function() { return result; }; // overwrite
    if (o instanceof Array) {
        result = [];
        for (var i=0; i<o.length; i++) {
            result[i] = cloneDR(o[i]);
        }
    } else {
        result = {};
        for (var prop in o)
            if (prop != gdcc)
                result[prop] = cloneDR(o[prop]);
            else if (set)
                result[prop] = cloneDR(cache);
    }
    if (set) {
        o[gdcc] = cache; // reset
    } else {
        delete o[gdcc]; // unset again
    }
    return result;
}

var b = cloneDR(a);

b.x = 'b';
b.nested.y = 'b';

And let's have a look at the output...

console.log(a, b);

a --> Object {
    x: "a",
    circ: Object {
        me: Object { ... }
    },
    nested: Object {
        y: "a"
    }
}

b --> Object {
    x: "b",
    circ: Object {
        me: Object { ... }
    },
    nested: Object {
        y: "b"
    }
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> false

The requirements are matched, but there are still some smaller issues, including changing the instance of nested and circ to Object.

The structure of trees that share a leaf won't be copied, they will become two independent leaves:

        [Object]                     [Object]
         /    \                       /    \
        /      \                     /      \
      |/_      _\|                 |/_      _\|  
  [Object]    [Object]   ===>  [Object]    [Object]
       \        /                 |           |
        \      /                  |           |
        _\|  |/_                 \|/         \|/
        [Object]               [Object]    [Object]

conclusion

The last solution using recursion and a cache, may not be the best, but it's a real deep-copy of the object. It handles simple properties, circular structures and nested object, but it will mess up the instance of them while cloning.

jsfiddle


Here's a modern solution that doesn't have the pitfalls of Object.assign() (does not copy by reference):

const cloneObj = (obj) => {
    return Object.keys(obj).reduce((dolly, key) => {
        dolly[key] = (obj[key].constructor === Object) ?
            cloneObj(obj[key]) :
            obj[key];
        return dolly;
    }, {});
};

This is an adaptation of A. Levy's code to also handle the cloning of functions and multiple/cyclic references - what this means is that if two properties in the tree which is cloned are references of the same object, the cloned object tree will have these properties point to one and the same clone of the referenced object. This also solves the case of cyclic dependencies which, if left unhandled, leads to an infinite loop. The complexity of the algorithm is O(n)

function clone(obj){
    var clonedObjectsArray = [];
    var originalObjectsArray = []; //used to remove the unique ids when finished
    var next_objid = 0;

    function objectId(obj) {
        if (obj == null) return null;
        if (obj.__obj_id == undefined){
            obj.__obj_id = next_objid++;
            originalObjectsArray[obj.__obj_id] = obj;
        }
        return obj.__obj_id;
    }

    function cloneRecursive(obj) {
        if (null == obj || typeof obj == "string" || typeof obj == "number" || typeof obj == "boolean") return obj;

        // Handle Date
        if (obj instanceof Date) {
            var copy = new Date();
            copy.setTime(obj.getTime());
            return copy;
        }

        // Handle Array
        if (obj instanceof Array) {
            var copy = [];
            for (var i = 0; i < obj.length; ++i) {
                copy[i] = cloneRecursive(obj[i]);
            }
            return copy;
        }

        // Handle Object
        if (obj instanceof Object) {
            if (clonedObjectsArray[objectId(obj)] != undefined)
                return clonedObjectsArray[objectId(obj)];

            var copy;
            if (obj instanceof Function)//Handle Function
                copy = function(){return obj.apply(this, arguments);};
            else
                copy = {};

            clonedObjectsArray[objectId(obj)] = copy;

            for (var attr in obj)
                if (attr != "__obj_id" && obj.hasOwnProperty(attr))
                    copy[attr] = cloneRecursive(obj[attr]);                 

            return copy;
        }       


        throw new Error("Unable to copy obj! Its type isn't supported.");
    }
    var cloneObj = cloneRecursive(obj);



    //remove the unique ids
    for (var i = 0; i < originalObjectsArray.length; i++)
    {
        delete originalObjectsArray[i].__obj_id;
    };

    return cloneObj;
}

Some quick tests

var auxobj = {
    prop1 : "prop1 aux val", 
    prop2 : ["prop2 item1", "prop2 item2"]
    };

var obj = new Object();
obj.prop1 = "prop1_value";
obj.prop2 = [auxobj, auxobj, "some extra val", undefined];
obj.nr = 3465;
obj.bool = true;

obj.f1 = function (){
    this.prop1 = "prop1 val changed by f1";
};

objclone = clone(obj);

//some tests i've made
console.log("test number, boolean and string cloning: " + (objclone.prop1 == obj.prop1 && objclone.nr == obj.nr && objclone.bool == obj.bool));

objclone.f1();
console.log("test function cloning 1: " + (objclone.prop1 == 'prop1 val changed by f1'));
objclone.f1.prop = 'some prop';
console.log("test function cloning 2: " + (obj.f1.prop == undefined));

objclone.prop2[0].prop1 = "prop1 aux val NEW";
console.log("test multiple references cloning 1: " + (objclone.prop2[1].prop1 == objclone.prop2[0].prop1));
console.log("test multiple references cloning 2: " + (objclone.prop2[1].prop1 != obj.prop2[0].prop1));

Consult http://www.w3.org/html/wg/drafts/html/master/infrastructure.html#safe-passing-of-structured-data for the W3C's "Safe passing of structured data" algorithm, intended to be implemented by browsers for passing data to eg web workers. However, it has some limitations, in that it does not handle functions. See https://developer.mozilla.org/en-US/docs/DOM/The_structured_clone_algorithm for more information, including an alternative algorithm in JS which gets you part of the way there.


From the Apple JavaScript Coding Guidelines:

// Create an inner object with a variable x whose default
// value is 3.
function innerObj()
{
        this.x = 3;
}
innerObj.prototype.clone = function() {
    var temp = new innerObj();
    for (myvar in this) {
        // this object does not contain any objects, so
        // use the lightweight copy code.
        temp[myvar] = this[myvar];
    }
    return temp;
}

// Create an outer object with a variable y whose default
// value is 77.
function outerObj()
{
        // The outer object contains an inner object.  Allocate it here.
        this.inner = new innerObj();
        this.y = 77;
}
outerObj.prototype.clone = function() {
    var temp = new outerObj();
    for (myvar in this) {
        if (this[myvar].clone) {
            // This variable contains an object with a
            // clone operator.  Call it to create a copy.
            temp[myvar] = this[myvar].clone();
        } else {
            // This variable contains a scalar value,
            // a string value, or an object with no
            // clone function.  Assign it directly.
            temp[myvar] = this[myvar];
        }
    }
    return temp;
}

// Allocate an outer object and assign non-default values to variables in
// both the outer and inner objects.
outer = new outerObj;
outer.inner.x = 4;
outer.y = 16;

// Clone the outer object (which, in turn, clones the inner object).
newouter = outer.clone();

// Verify that both values were copied.
alert('inner x is '+newouter.inner.x); // prints 4
alert('y is '+newouter.y); // prints 16

Steve


Jan Turon's answer above is very close, and may be the best to use in a browser due to compatibility issues, but it will potentially cause some strange enumeration issues. For instance, executing:

for ( var i in someArray ) { ... }

Will assign the clone() method to i after iterating through the elements of the array. Here's an adaptation that avoids the enumeration and works with node.js:

Object.defineProperty( Object.prototype, "clone", {
    value: function() {
        if ( this.cloneNode )
        {
            return this.cloneNode( true );
        }

        var copy = this instanceof Array ? [] : {};
        for( var attr in this )
        {
            if ( typeof this[ attr ] == "function" || this[ attr ] == null || !this[ attr ].clone )
            {
                copy[ attr ] = this[ attr ];
            }
            else if ( this[ attr ] == this )
            {
                copy[ attr ] = copy;
            }
            else
            {
                copy[ attr ] = this[ attr ].clone();
            }
        }
        return copy;
    }
});

Object.defineProperty( Date.prototype, "clone", {
    value: function() {
        var copy = new Date();
        copy.setTime( this.getTime() );
        return copy;
    }
});

Object.defineProperty( Number.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( Boolean.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( String.prototype, "clone", { value: function() { return this; } } );

This avoids making the clone() method enumerable because defineProperty() defaults enumerable to false.


There are many answers, but none that mentions Object.create from ECMAScript 5, which admittedly does not give you an exact copy, but sets the source as the prototype of the new object.

Thus, this is not an exact answer to the question, but it is a one-line solution and thus elegant. And it works best for 2 cases:

  1. Where such inheritance is useful (duh!)
  2. Where the source object won't be modified, thus making the relation between the 2 objects a non issue.

Example:

var foo = { a : 1 };
var bar = Object.create(foo);
foo.a; // 1
bar.a; // 1
foo.a = 2;
bar.a; // 2 - prototype changed
bar.a = 3;
foo.a; // Still 2, since setting bar.a makes it an "own" property

Why do I consider this solution to be superior? It's native, thus no looping, no recursion. However, older browsers will need a polyfill.


Interested in cloning simple objects:

JSON.parse(JSON.stringify(json_original));

Source : How to copy JavaScript object to new variable NOT by reference?


Ok so this might be the very best option for shallow copying. If follows the many examples using assign, but it also keeps the inheritance and prototype. It's so simple too and works for most array-like and Objects except those with constructor requirements or read-only properties. But that means it fails miserably for TypedArrays, RegExp, Date, Maps, Sets and Object versions of primitives (Boolean, String, etc..).

function copy ( a ) { return Object.assign( new a.constructor, a ) }

Where a can be any Object or class constructed instance, but again not be reliable for thingies that use specialized getters and setters or have constructor requirements, but for more simple situations it rocks. It does work on arguments as well.

You can also apply it to primitives to get strange results, but then... unless it just ends up being a useful hack, who cares.

results from basic built-in Object and Array...

> a = { a: 'A', b: 'B', c: 'C', d: 'D' }
{ a: 'A', b: 'B', c: 'C', d: 'D' }
> b = copy( a )
{ a: 'A', b: 'B', c: 'C', d: 'D' }
> a = [1,2,3,4]
[ 1, 2, 3, 4 ]
> b = copy( a )
[ 1, 2, 3, 4 ]

And fails because of mean get/setters, constructor required arguments or read-only properties, and sins against the father.

> a = /\w+/g
/\w+/g
> b = copy( a )  // fails because source and flags are read-only
/(?:)/
> a = new Date ( '1/1/2001' )
2000-12-31T16:00:00.000Z
> b = copy( a )  // fails because Date using methods to get and set things
2017-02-04T14:44:13.990Z
> a = new Boolean( true )
[Boolean: true]
> b = copy( a )  // fails because of of sins against the father
[Boolean: false]
> a = new Number( 37 )
[Number: 37]
> b = copy( a )  // fails because of of sins against the father
[Number: 0]
> a = new String( 'four score and seven years ago our four fathers' )
[String: 'four score and seven years ago our four fathers']
> b = copy( a )  // fails because of of sins against the father
{ [String: ''] '0': 'f', '1': 'o', '2': 'u', '3': 'r', '4': ' ', '5': 's', '6': 'c', '7': 'o', '8': 'r', '9': 'e', '10': ' ', '11': 'a', '12': 'n', '13': 'd', '14': ' ', '15': 's', '16': 'e', '17': 'v', '18': 'e', '19': 'n', '20': ' ', '21': 'y', '22': 'e', '23': 'a', '24': 'r', '25': 's', '26': ' ', '27': 'a', '28': 'g', '29': 'o', '30': ' ', '31': 'o', '32': 'u', '33': 'r', '34': ' ', '35': 'f', '36': 'o', '37': 'u', '38': 'r', '39': ' ', '40': 'f', '41': 'a', '42': 't', '43': 'h', '44': 'e', '45': 'r', '46': 's' } 

I'm providing an answer to this question, because I do not see any native, recursive implementations here that resolve the problem of DOM elements.

The problem there is that <element> has parent and child attributes, that link to other elements with parent and child values, which point back to the original <element>, causing either an infinite recursive or cyclic redundancy.

If your object is something safe and simple like

{
    '123':456
}

...then any other answer here will probably work.

But if you have...

{
    '123':<reactJSComponent>,
    '456':document.createElement('div'),
}

...then you need something like this:

    // cloneVariable() : Clone variable, return null for elements or components.
var cloneVariable = function (args) {
    const variable = args.variable;

    if(variable === null) {
            return null;
    }

    if(typeof(variable) === 'object') {
            if(variable instanceof HTMLElement || variable.nodeType > 0) {
                    return null;
            }

            if(Array.isArray(variable)) {
                    var arrayclone = [];

                    variable.forEach((element) => {
                            arrayclone.push(cloneVariable({'variable':element}));
                    });

                    return arrayclone;
            }

            var objectclone = {};

            Object.keys(variable).forEach((field) => {
                    objectclone[field] = cloneVariable({'variable':variable[field]});
            });

            return objectclone;
    }

    return variable;
}

You can clone an object and remove any reference from the previous one using a single line of code. Simply do:

var obj1 = { text: 'moo1' };
var obj2 = Object.create(obj1); // Creates a new clone without references

obj2.text = 'moo2'; // Only updates obj2's text property

console.log(obj1, obj2); // Outputs: obj1: {text:'moo1'}, obj2: {text:'moo2'}

For browsers / engines that do not currently support Object.create you can use this polyfill:

// Polyfill Object.create if it does not exist
if (!Object.create) {
    Object.create = function (o) {
        var F = function () {};
        F.prototype = o;
        return new F();
    };
}

From this article: How to copy arrays and objects in Javascript by Brian Huisman:

Object.prototype.clone = function() {
  var newObj = (this instanceof Array) ? [] : {};
  for (var i in this) {
    if (i == 'clone') continue;
    if (this[i] && typeof this[i] == "object") {
      newObj[i] = this[i].clone();
    } else newObj[i] = this[i]
  } return newObj;
};

The most correct to copy object is use Object.create:

Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));

Such a notation will make identically the same object with right prototype and hidden properties.


According to the Airbnb JavaScript Style Guide with 404 contributors:

Prefer the object spread operator over Object.assign to shallow-copy objects. Use the object rest operator to get a new object with certain properties omitted.

// very bad
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); // this mutates `original` ?_?
delete copy.a; // so does this

// bad
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }

// good
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }

const { a, ...noA } = copy; // noA => { b: 2, c: 3 }

Also I'd like to warn you that even though Airbnb hardly recommends the object spread operator approach. Keep in mind that Microsoft Edge still does not support this 2018 feature yet.

ES2016+ Compat table >>


function clone(obj)
{
    var cloneObj = Object.create(obj);

    return cloneObj;
}

In Javascript objects individually inherit another object (Prototypal inheritance). Object.create(obj) returns an object that is a sub-object or child object of obj. In the above function it will effectively return a copy of the object.

However, This is a very odd way to clone because I am not using inheritance for its real purpose.


I've tried this in the case of a scalar object and it works for me:

function binder(i) {
  return function () {
    return i;
  };
}

a=1;
b=binder(a)(); // copy value of a into b

alert(++a); // 2
alert(b); // still 1

Regards.


In ECMAScript 6 there is Object.assign method, which copies values of all enumerable own properties from one object to another. For example:

var x = {myProp: "value"};
var y = Object.assign({}, x); 

But be aware that nested objects are still copied as reference.


An elegant way to clone a Javascript object in one line of code

An Object.assign method is part of the ECMAScript 2015 (ES6) standard and does exactly what you need.

var clone = Object.assign({}, obj);

The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object.

Read more...

The polyfill to support older browsers:

if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

      var to = Object(target);
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }
        nextSource = Object(nextSource);

        var keysArray = Object.keys(nextSource);
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}

If your object is a class (e.g. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes):

var copiedObject = jQuery.extend(true, {}, originalObject);
copiedObject.__proto__ = originalObject.__proto__;

Then in copiedObject you have a deep-copied instance of originalObject class with all its methods.


Simple

var restore = { name:'charlesi',
age:9}
var prev_data ={
name: 'charles'
age : 10
}

var temp = JSON.stringify(prev_data)
restore = JSON.parse(temp)

restore = {
name:'charlie',
age : 12}

output prev_data:

{
name: 'charles'
age : 10
} 

If there are no circular dependencies in your object, I suggest using one of the other answers or jQuery's copy methods, as they all seem quite effective.

If there are circular dependencies (i.e., two sub-objects link to each other), you are kind of screwed as there is (from a theoretical perspective) no way to solve this issue elegantly.


My favorite & elegant JS objects clone solution is

function CloneObject() {}
function cloneObject(o) {
   CloneObject.prototype = o;
   return new CloneObject();
}

Use cloneObject(object) to get a clone of JS object.

Unlike many copy solutions this clone keeps prototype relationship in cloned object.


If you got an Object with Functions you can do it with JSONfn, see http://www.eslinstructor.net/jsonfn/.

var obj= {
    name:'Marvin',
    getName :  function(){
      return this.name;
    }
}
var cobj = JSONfn.parse(JSONfn.stringify(obj));

In ES-6 you can simply use Object.assign(...). Ex:

let obj = {person: 'Thor Odinson'};
let clone = Object.assign({}, obj);

A good reference is here: https://googlechrome.github.io/samples/object-assign-es6/


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to clone

git clone error: RPC failed; curl 56 OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 10054 git: fatal: I don't handle protocol '??http' How to make a copy of an object in C# How create a new deep copy (clone) of a List<T>? "fatal: Not a git repository (or any of the parent directories)" from git status How to copy java.util.list Collection How to jQuery clone() and change id? Copying a HashMap in Java jquery clone div and append it after specific div jQuery Clone table row

Examples related to javascript-objects

Cannot read property 'style' of undefined -- Uncaught Type Error Is this a good way to clone an object in ES6? What’s the difference between “{}” and “[]” while declaring a JavaScript array? Comparing two arrays of objects, and exclude the elements who match values into new array in JS Converting JavaScript object with numeric keys into array From an array of objects, extract value of a property as array How to copy JavaScript object to new variable NOT by reference? Remove property for all objects in array Using curl POST with variables defined in bash script functions How to sum the values of a JavaScript object?