253

I have a big object with much data. And i want to clone this in other variable. When i set some param of the instance B has the same result in the original object:

var obj = {a: 25, b: 50, c: 75};
var A = obj;
var B = obj;

A.a = 30;
B.a = 40;

alert(obj.a + " " + A.a + " " + B.a); // 40 40 40

My output should be 25 30 40. Any ideas?

EDIT

Thanks Everyone. I change the code of dystroy and this is my result:

Object.prototype.clone = Array.prototype.clone = function() {
    if (Object.prototype.toString.call(this) === '[object Array]') {
        var clone = [];
        for (var i = 0; i < this.length; i++)
            clone[i] = this[i].clone();

        return clone;
    } else if (typeof(this) === "object") {
        var clone = {};
        for (var prop in this) {
            if (this.hasOwnProperty(prop))
                clone[prop] = this[prop].clone();
            }
        return clone;
    } else {
        return this;
    }
}

var obj = {a: 25, b: 50, c: 75};
var A = obj.clone();
var B = obj.clone();
A.a = 30;
B.a = 40;
alert(obj.a + " " + A.a + " " + B.a);

var arr = [25, 50, 75];
var C = arr.clone();
var D = arr.clone();
C[0] = 30;
D[0] = 40;
alert(arr[0] + " " + C[0] + " " + D[0]);
Alex Vergara
  • 1,766
  • 1
  • 10
  • 29
Enzo
  • 4,111
  • 4
  • 21
  • 33
  • 3
    See [What is the most efficient way to clone a JavaScript object?](http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-a-javascript-object) – Rob W Oct 02 '12 at 12:22
  • 4
    @RobW—there's an awful lot of junk in that thread, including different ideas on what a "clone" is. – RobG Oct 02 '12 at 12:45
  • 2
    +1 And the accepted and upvoted answer is, with respect to his author, just a comment on another answer using jQuery. That thread went full banana... – Denys Séguret Oct 02 '12 at 12:47
  • 7
    You can simply use `copy = Object.create(originalObj);` but you may want to use `copy = JSON.parse(JSON.stringify(originalObj));` to avoid any reference in sub objects (Deep Copy). – Matthieu Chavigny Apr 12 '19 at 09:11
  • 1
    Best way is << let B = JSON.parse(JSON.stringify(A)) >> As it is like a stream of data. The concept of reference is due to deep copy & shallow copy. In Deep copy reference will not be there, where as it will be there in shallow copy like << let B = A >>. Deep copy has some demerit like in custom object, nested object. So, read properly & apply whichever suits you – Satish Patro May 15 '19 at 05:59
  • 1
    var A = {...obj} var B = {...obj} Spread operator –  May 17 '19 at 09:37
  • I know you're looking for separate objects. But I had the problem, that I often had object arrays. To duplicate an **object array** you can use the **`.slice(0)`** method, like: `let objArr = [{ id: 1, name: 'one' },{ id: 2, name: 'two' }];` `let objArrCopy = objArr.slice(0);` `objArr.pop();` `console.log(objArr);` `console.log(objArrCopy);` Duplicated and without references. :) – Froschkoenig84 May 28 '19 at 17:46

4 Answers4

276

If you use an = statement to assign a value to a var with an object on the right side, javascript will not copy but reference the object.

Spoiler : using JSON.parse(JSON.stringify(obj)) may work but is costly, and might throw a TypeError as in

const a = {};
const b = { a };
a.b = b;
const clone = JSON.parse(JSON.stringify(a));
/* Throws
Uncaught TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Object'
    |     property 'b' -> object with constructor 'Object'
    --- property 'a' closes the circle
    at JSON.stringify (<anonymous>)
    at <anonymous>:4:6
*/

As of es2015, if you want a shallow copy (clone the object, but keeping deep refences in the inner structure) you can use destructuring :

const obj = { foo: { bar: "baz" } };
const shallowClone = { ...obj };

shallowClone is a new object, but shallowClone.foo holds a reference to the same object as obj.foo.

You can use lodash's clone method, which does the same, if you don't have access to the spread operator.

var obj = {a: 25, b: 50, c: 75};
var A = _.clone(obj);

Or lodash's cloneDeep method if your object has multiple object levels

var obj = {a: 25, b: {a: 1, b: 2}, c: 75};
var A = _.cloneDeep(obj);

Or lodash's merge method if you mean to extend the source object

var obj = {a: 25, b: {a: 1, b: 2}, c: 75};
var A = _.merge({}, obj, {newkey: "newvalue"});

Or you can use jQuerys extend method:

var obj = {a: 25, b: 50, c: 75};
var A = $.extend(true,{},obj);

Here is jQuery 1.11 extend method's source code :

jQuery.extend = jQuery.fn.extend = function() {
    var src, copyIsArray, copy, name, options, clone,
        target = arguments[0] || {},
        i = 1,
        length = arguments.length,
        deep = false;

    // Handle a deep copy situation
    if ( typeof target === "boolean" ) {
        deep = target;

        // skip the boolean and the target
        target = arguments[ i ] || {};
        i++;
    }

    // Handle case when target is a string or something (possible in deep copy)
    if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
        target = {};
    }

    // extend jQuery itself if only one argument is passed
    if ( i === length ) {
        target = this;
        i--;
    }

    for ( ; i < length; i++ ) {
        // Only deal with non-null/undefined values
        if ( (options = arguments[ i ]) != null ) {
            // Extend the base object
            for ( name in options ) {
                src = target[ name ];
                copy = options[ name ];

                // Prevent never-ending loop
                if ( target === copy ) {
                    continue;
                }

                // Recurse if we're merging plain objects or arrays
                if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
                    if ( copyIsArray ) {
                        copyIsArray = false;
                        clone = src && jQuery.isArray(src) ? src : [];

                    } else {
                        clone = src && jQuery.isPlainObject(src) ? src : {};
                    }

                    // Never move original objects, clone them
                    target[ name ] = jQuery.extend( deep, clone, copy );

                // Don't bring in undefined values
                } else if ( copy !== undefined ) {
                    target[ name ] = copy;
                }
            }
        }
    }

    // Return the modified object
    return target;
};

var item ={ 'a': 1, 'b': 2}
Object.assign({}, item);

UPDATE: 05/31/2023 a new global function was release that allows DEEP COPY called window.structuredClone()

Bins
  • 65
  • 7
Armel Larcier
  • 15,747
  • 7
  • 68
  • 89
  • 8
    I'll be damned. Sometimes jQuery IS the answer. I was about to beat my head through writing a function that does pretty much this, and here it is. – erfling Feb 15 '15 at 02:19
  • 3
    Underscore can also be used: `var A = _.extend({},obj);` – Edwin Stoteler Jan 18 '16 at 11:10
  • Does this mean you have to use an external library to do the job? – kojow7 Jul 07 '17 at 06:48
  • @kojow7 if you need to copy complex deep objects, I'd advise to use a library like lodash. If you know the object's structure in advance you could implement a copy function yourself though. – Armel Larcier Jul 23 '17 at 06:02
  • 96
    Vanilla javascript quick and dirty `var A = JSON.parse(JSON.stringify(obj)); ` – mintedsky Oct 10 '17 at 20:44
  • 10
    mintedsky's solution works, but it feels so, so dirty... –  Jul 06 '18 at 13:50
  • Thanks for the solution it saved my time.. :) – Bhanu Pratap Aug 24 '18 at 16:22
  • If you are okay with adding all of jQuery to your project for one small snippet of code lol .. – user3044394 Sep 03 '18 at 11:17
  • With ES6 we can use spread operator and copy object without reference. Instead of doing this var B = obj; we just need to use var B = {...obj}; – sharad jain Nov 11 '19 at 10:00
  • 1
    Yes but beware that if the object’s properties are arrays or objects themselves, they will be passed as references as well. – Armel Larcier Nov 11 '19 at 11:42
  • 14
    Also you could create `let a = {...obj}` – jad Nov 19 '19 at 17:48
  • The solution @Jargal proposed is the fastest and should be marked the correct answer as of Nov '19. The spread operator did not exist 7 years ago when this thread was started though. – osynligsebastian Mar 18 '20 at 15:34
  • 7
    WARNING: "When you have nested data in an array or object the spread operator will create a deep copy of the top most data and a shallow copy of the nested data." [The Spread Operator: Deep and Shallow copies](https://medium.com/@kevinlai76/the-spread-operator-deep-and-shallow-copies-d193ac9b58bf) - so I still use the JSON.parse method. – mmarlow Oct 09 '20 at 11:16
  • Solution proposed by @mintedsky should be marked as the correct answer. This is a 100% failsafe approach as opposed to using the spread operator. – hpl002 May 04 '21 at 08:32
  • 1
    Updated my answer @mmarlow. `JSON.parse(JSON.stringify(obj))` may throw because of a circular structure. – Armel Larcier May 07 '21 at 23:10
  • @Jargal, I just tried the spread option and it doesn't work for me for the object references within the original object. – user4002112 Mar 20 '22 at 01:33
146

While this isn't cloning, one simple way to get your result is to use the original object as the prototype of a new one.

You can do this using Object.create:

var obj = {a: 25, b: 50, c: 75};
var A = Object.create(obj);
var B = Object.create(obj);

A.a = 30;
B.a = 40;

alert(obj.a + " " + A.a + " " + B.a); // 25 30 40

This creates a new object in A and B that inherits from obj. This means that you can add properties without affecting the original.

To support legacy implementations, you can create a (partial) shim that will work for this simple task.

if (!Object.create)
    Object.create = function(proto) {
        function F(){}
        F.prototype = proto;
        return new F;
    }

It doesn't emulate all the functionality of Object.create, but it'll fit your needs here.

I Hate Lazy
  • 47,415
  • 13
  • 86
  • 77
  • 7
    I think that A doesn't directly contain b with this solution, so it's a very different object. – Denys Séguret Oct 02 '12 at 12:34
  • 1
    +1 for Object.create(...). So if I receive a JSON string rapresenting an object and I want to process it and return a new object of the same type, Object.create is all that I need. – Alberto De Caro Oct 02 '12 at 12:35
  • @dystroy: Yes, that is explained in my answer. *"While this isn't cloning,..."* and *"This creates a new object in A and B that inherits from obj."* – I Hate Lazy Oct 02 '12 at 12:40
  • @ADC: If the JSON has already been parsed, then yes, you can create new objects that inherits from the original so that you can make local modifications without affecting the original. But you should be aware that if the JSON has nested structures, you would need to traverse through and do the same for all nested objects. – I Hate Lazy Oct 02 '12 at 12:43
  • I wanted to point what is maybe not clear : you can't iterate on own properties of A like you do on obj. But I agree that, depending on what OP wants to do with his objects, this may be a solution. – Denys Séguret Oct 02 '12 at 12:45
  • @dystroy: That's a good point. Some people put up the `.hasOwnProperty` guard on every enumeration for fear of `Object.prototype` extensions. That's why I always say that the better approach is to ensure `Object.prototype` isn't enhanced with enumerables, because sometimes you *want* prototyped properties to be enumerated. – I Hate Lazy Oct 02 '12 at 12:48
  • You may find [Javascript cloned object looses its prototype functions](http://stackoverflow.com/questions/10151216/javascript-cloned-object-looses-its-prototype-functions) ineresting. – RobG Oct 03 '12 at 01:23
  • @RobG: Did you post that comment under the correct answer? – I Hate Lazy Oct 03 '12 at 01:26
  • Yes, it's another approach to using prototypes for cloning. – RobG Oct 03 '12 at 03:22
  • been searching for this for ages, I needed a new object created because I push to an array from another array multiple of the same object and reference just wont work for what I need. Great help! – Joe Lloyd Dec 26 '15 at 23:13
18

You could define a clone function.

I use this one :

function goclone(source) {
    if (Object.prototype.toString.call(source) === '[object Array]') {
        var clone = [];
        for (var i=0; i<source.length; i++) {
            clone[i] = goclone(source[i]);
        }
        return clone;
    } else if (typeof(source)=="object") {
        var clone = {};
        for (var prop in source) {
            if (source.hasOwnProperty(prop)) {
                clone[prop] = goclone(source[prop]);
            }
        }
        return clone;
    } else {
        return source;
    }
}

var B = goclone(A);

It doesn't copy the prototype, functions, and so on. But you should adapt it (and maybe simplify it) for you own need.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • 2
    There is no need to use a different method for "cloning" an Array to cloning any other object. If you use a loop from `0` to `length`, then the copy may have properties that don't exist on the original array so `for..in` is a better choice in this case. Also, there is no need to test `source[prop]`, why not copy falsey properties? – RobG Oct 02 '12 at 12:25
  • You might use source.constructor to avoid a test (I didn't use it because this is adapted from a code in which I wanted to be sure to remove prototype) but I fail to see how this would add unwanted properties. I've made [a fiddle](http://jsfiddle.net/dystroy/U3jHd/). – Denys Séguret Oct 02 '12 at 12:31
  • @dystroy: It would if it's a sparse Array. Also, sometimes an Array has extra non numeric properties that are carried along for convenience. A numeric iteration will fail to clone those. – I Hate Lazy Oct 02 '12 at 12:32
  • ...oh wait, maybe not, but you are skipping all "falsey" values in the Array because of the `if(source[i])`, so it handles the sparse array, but in a destructive manner. You should be doing `if (i in source)` or `if (source.hasOwnProperty(i))` – I Hate Lazy Oct 02 '12 at 12:35
  • @user1689607 Look at my fiddle : it was made with a sparse array. I fixed for the falsey values (my [original code](http://canop.org/blog/?p=125) was *designed* to remove null, false, 0 and so on for lighter communication with a Go server...). – Denys Séguret Oct 02 '12 at 12:36
  • @dystroy—for sparse arrays, it will add missing members. e.g. in `var a = goClone([,,1]`, the original array only has one member: a['2'], but the clone will have 3 (at 0, 1 and 2). I just don't see the need to use a for loop for one and for..in for the other when for..in does both. – RobG Oct 02 '12 at 13:39
10

A and B reference the same object, so A.a and B.a reference the same property of the same object.

Edit

Here's a "copy" function that may do the job, it can do both shallow and deep clones. Note the caveats. It copies all enumerable properties of an object (not inherited properties), including those with falsey values (I don't understand why other approaches ignore them), it also doesn't copy non–existent properties of sparse arrays.

There is no general copy or clone function because there are many different ideas on what a copy or clone should do in every case. Most rule out host objects, or anything other than Objects or Arrays. This one also copies primitives. What should happen with functions?

So have a look at the following, it's a slightly different approach to others.

/* Only works for native objects, host objects are not
** included. Copies Objects, Arrays, Functions and primitives.
** Any other type of object (Number, String, etc.) will likely give 
** unexpected results, e.g. copy(new Number(5)) ==> 0 since the value
** is stored in a non-enumerable property.
**
** Expects that objects have a properly set *constructor* property.
*/
function copy(source, deep) {
   var o, prop, type;

  if (typeof source != 'object' || source === null) {
    // What do to with functions, throw an error?
    o = source;
    return o;
  }

  o = new source.constructor();

  for (prop in source) {

    if (source.hasOwnProperty(prop)) {
      type = typeof source[prop];

      if (deep && type == 'object' && source[prop] !== null) {
        o[prop] = copy(source[prop]);

      } else {
        o[prop] = source[prop];
      }
    }
  }
  return o;
}
RobG
  • 142,382
  • 31
  • 172
  • 209
  • 1
    "copy" is a reserved word. – Chris Scott Jun 11 '17 at 03:08
  • 1
    @ChrisScott—not in the [*current version of ECMA-262*](http://ecma-international.org/ecma-262/7.0/index.html#sec-reserved-words) or the [*next one*](https://tc39.github.io/ecma262/#sec-reserved-words). – RobG Jun 11 '17 at 05:31