16

Possible Duplicate:
How to clone js object?

This is another way to create a javascript object (using object literal notation instead of function):

user = {
  name: "Foo",
  email: "bar@baz.com"
}

Is there a way to clone this object or is it a singleton?

Community
  • 1
  • 1
never_had_a_name
  • 90,630
  • 105
  • 267
  • 383
  • 3
    JavaScript object != JSON object. The example you provided is a JavaScript object literal; I updated your post accordingly. – Matt Ball Sep 22 '10 at 22:16
  • good question! I'll always think that user2 = user will make a copy, but don't. – Topera Sep 22 '10 at 22:16
  • 1
    Shortest 'answer': yes and yes. ;) – Marcel Korpel Sep 22 '10 at 22:24
  • The answer you selected is still not a deep copy..my solution is still the best. – vol7ron Oct 10 '10 at 20:21
  • The answer you selected will not produce a different result than using `var user2 = user;`. Only the `clone` function is causing the constructor name to be changed. **Thats not cloning**, thats a duplicate reference !! – Om Shankar Feb 22 '13 at 17:18
  • @OmShankar, that's not accurate. See my response to MarzSocks below my answer. – Dagg Nabbit Oct 26 '13 at 22:39
  • @DaggNabbit, your code is doubtful and does not achieve its purpose. Check both my comments, below the one you are pointing. The created object has a reference to the same object. So that's not a clone. We would not need a clone in JS, if we wanted to do what your method is doing, since that is readily possible in JS without any tricks. – Om Shankar Oct 28 '13 at 09:23
  • @DaggNabbit, also, this is JavaScript. So the reference you have linked explaining how a clone is not a shallow copy or a deep copy, is that person's point of view. As per the definition of a `clone`, may it be JavaScript object or real world humans, only the original properties are preserved while at creation. They don't need to follow each other for every state or property change. – Om Shankar Oct 28 '13 at 09:30
  • @OmShankar, please stop trying to argue your way out of a hole. The code clearly achieved its purpose, as it helped the asker. If by "without any tricks" you are referring to `Object.create`, please note the date on these posts. And the rest of your comments are completely nonsensical, unless you take "deep copy" to be the only acceptable definition of "clone," which is absurd. – Dagg Nabbit Oct 29 '13 at 00:08
  • @DaggNabbit, Why is changing the property of original object changes that of the clone, in your method? That's against cloning. May be this is the simplest way I can question your intelligence which is failing to understand doubts after so many comments :) – Om Shankar Oct 29 '13 at 10:05
  • @OmShankar, like it or not, this is an accepted definition of cloning in prototypal languages (arguably the most common), and that's just the way it works. And of course changing a property on the original object *does not* change any of the clone's *own* properties. And if we're going to question each other's intelligence, I'd call in to question your original statement that this is the same as doing `var user2 = user;`, because of course it's not; the new object can have its own properties which shadow the original. I'm sorry you don't like this definition of cloning, but please get over it. – Dagg Nabbit Oct 29 '13 at 13:53
  • Changing the properties of the original object **IS** changing the clone's properties. That's what people have commented _there_ as well has here. Edit: Acc to you, John Resig also understands cloning in a wrong way, then. :) – Om Shankar Oct 29 '13 at 14:05
  • It is not changing the clone's *own* properties. This is why I stressed *own*. Own, as in `hasOwnProperty`. jQuery's `clone` is clearly named after `cloneNode`, which is a DOM function and has little to do with JavaScript or the usual definition of "clone" in prototypal languages (DOM stuff is language-agnostic). – Dagg Nabbit Nov 03 '13 at 04:07

5 Answers5

29

Try this:

var clone = (function(){ 
  return function (obj) { Clone.prototype=obj; return new Clone() };
  function Clone(){}
}());

Here's what's going on.

  • Clone is a dummy constructor.
  • We assign the object we want to clone to the Clone constructor's prototype.
  • We call Clone using 'new', so the constructed object has the original object as its constructor's prototype aka (non-standard) __proto__.

The cloned object will share all the properties of the original object without any copies of anything being made. If properties of the cloned object are assigned new values, they won't interfere with the original object. And no tampering of built-ins is required.

Keep in mind that an object property of the newly-created object will refer to the same object as the eponymous property of the cloned object. Assigning a new value to a property of the clone won't interfere with the original, but assigning values to the clone's object properties will.


Try this in chrome or firebug console:

var user = {
  name: "Foo",
  email: "bar@baz.com"
}

var clonedUser = clone(user);

console.dir(clonedUser);

A detailed explanation of this cloning technique can be found here.

Dagg Nabbit
  • 75,346
  • 19
  • 113
  • 141
  • 2
    `user={name:"",email:"",obj:{a:"A"}}; clonedUser=clone(user);`, `clonedUser.obj.a="B";` you'll find `user.obj.a == "B"` – vol7ron Sep 23 '10 at 00:22
  • This looks really similar to Chris J's answer too. – vol7ron Sep 23 '10 at 00:27
  • vol7ron: yes, because user.obj and clonedUser.obj refer to the same object. Assigning a new value to newUser's `obj` property will not exhibit this behavior. The request was for a clone, not a copy, and not a deep copy. See the link at the end of my answer. – Dagg Nabbit Sep 23 '10 at 00:31
  • @no: very good, if you edit the answer, I'll remove my downvote :) That is correct, but there is a big distinction in the article's definition of the programmatic `clone` and the vernacular definition of a clone. – vol7ron Sep 23 '10 at 00:40
  • Still article definition `A` cloned is `B`. `A` makes changes to property, `B` sees it. `B` makes changes to property, `A` doesn't give a ----. In your example, they would both share a nested object. If `B` makes changes to that object's property, `A` should not see the change. In all, cloning is discouraged, deep copying is encouraged. – vol7ron Sep 23 '10 at 00:49
  • Nah, clone B won't see changes to properties of original object A after the clone is made... try it and see for yourself. Unless you mean changes to properties of an object property shared by the clone and the original, of course. – Dagg Nabbit Sep 23 '10 at 00:51
  • The later, where a property already existed of the nested object. Changes of that property will be seen in the superclass. Even adding a property to that internal object is seen in both. – vol7ron Sep 23 '10 at 00:52
  • Yes, this is the desired behavior for a shallow operation like this. A deep clone function could easily be made if required. Again, the question asked for a clone, not a copy, a deep copy, or a deep clone. – Dagg Nabbit Sep 23 '10 at 00:55
  • I'm really curious what **ajsie** really wanted, my guess is a deep copy. – vol7ron Sep 23 '10 at 00:58
  • @vol7ron. I wasn't clear in my post what I meant, didn't know there was shallow and deep copy/clone. Is copy and clone the same thing btw? However, I'm looking for a way to make identical copies, that is to say deep copy I guess, or deep clone =) Does that answer still stand? – never_had_a_name Sep 23 '10 at 10:19
  • No, I suspected you'd want a complete copy; you'd want my solution, despite all the flame-war downvotes – vol7ron Sep 23 '10 at 15:59
  • This is the same as doing the following: var obj2 = obj1; There is a pass by reference and its not a true new instance of the object. – MarzSocks Oct 26 '13 at 15:32
  • @MarzSocks, no, it's not. Try it, `obj2 === obj1` will return false. It creates a new object with the old object in the prototype chain, not a reference to the existing object. – Dagg Nabbit Oct 26 '13 at 22:38
  • @DaggNabbit, Absolutely Wrong !! Create an object: `var abc = {a: 1, b: 2}` and then try doing `var def = clone(abc);` with your method. **Notice that** changing `abc.a` also changes `def.a`, LOL. How is that cloning?? That can happen only if they point to the same reference. – Om Shankar Oct 28 '13 at 09:18
  • @DaggNabbit, also, your code is doubtful. As in the IIF, `function Clone(){}` is hoisted, so putting it after `return` statement is confusing. – Om Shankar Oct 28 '13 at 09:21
  • @OmShankar, I covered your `abc.a` point in my answer already. Function hoisting is a part of JavaScript, and is not ambiguous. I'm not sure why this is confusing to you. – Dagg Nabbit Oct 28 '13 at 23:56
  • @DaggNabbit, yes it is a part. But putting a function definition after main logic is confusing. Confusing does not necessarily mean not-understandable. Something understandable can also be confusing, in purpose. – Om Shankar Oct 29 '13 at 09:55
  • w(._.)w alrighty then – Dagg Nabbit Oct 29 '13 at 13:44
11

You can use JSON object (present in modern browsers):

var user = {name: "Foo", email: "bar@baz.com" } 
var user2 = JSON.parse(JSON.stringify(user))

user2.name = "Bar";
alert(user.name + " " + user2.name); // Foo Bar

See in jsfiddle.


EDIT

If you need this in older browsers, see http://www.json.org/js.html.

Topera
  • 12,223
  • 15
  • 67
  • 104
  • 1
    hmm... not going to downvote you but this is just silly, in my opinion. first of all, if you are going to use JSON, you WILL need to include json2.js in your page because there are still current browsers without native json and there will be in common use those that are not current for some time. Either write or borrow an extend implementation or include a library that has one. – Sky Sanders Sep 23 '10 at 05:15
  • I'm just giving another way to do this. If a site already have json2.js, it works. – Topera Sep 23 '10 at 13:15
  • 1
    If an object has both `properties` and `methods`, then my friend, using this JSON style, `methods` are **not cloned** – Om Shankar Feb 22 '13 at 17:14
  • 6
    It's actually not so silly... For example, if you are creating an app for an embedded system, so you always know what browser it is going to run on; and you know it's a data object (so you don't care if the methods get cloned), then this is easy, clean, and safe. It won't work for all applications, but it's perfect for what I want! Thanks! – user435779 Apr 16 '13 at 16:14
4

I like to use this:

if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        var F = function () {};
        F.prototype = o;
    return new F();
    };
}

then any object I want to clone can be done as:

user = {
    name: "Foo",
    email: "bar@baz.com"
};
var user2 = Object.create(user);

As shown in (or similar to) JavaScript The Good Parts

Chris J
  • 823
  • 1
  • 9
  • 16
  • 1
    You shouldn't do this; see [Kangax' answer](http://stackoverflow.com/questions/3075308/what-modernizer-scripts-exist-for-the-new-ecmascript-5-functions/3075818#3075818) – Marcel Korpel Sep 22 '10 at 23:14
  • 2
    @Marcel Thanks for pointing that out. I'll leave my answer as is and recommend Kangax' explanation as a good read. – Chris J Sep 23 '10 at 00:10
  • @Marcel/Chris +1; Kangax's answer is only that create doesn't take two properties everywhere. My feeling is if everyone used this method, then it would force vendors to comply to standards. I didn't use FF initially because it didn't display everything correctly, now the web got smarter and FF has made modifications to work better in quirksmode. The same will be true if programmers confine to standards and push the browsers that accept them. – vol7ron Sep 23 '10 at 00:37
  • Would be good if Javascript could provide an easy way to clone objects – never_had_a_name Sep 23 '10 at 07:08
  • I like that one best of all. – Mike Thornley Apr 15 '13 at 17:40
2

Most of the javascript frameworks have good support for object cloning.

var a= {'key':'value'};
var b= jQuery.extend( true, {}, a );
Jonathan Vanasco
  • 15,111
  • 10
  • 48
  • 72
0
Object.prototype.clone = function clone(obj) {
                           obj = obj || this;
                           var new_obj  = {};

                           for( var p in obj ) {
                             if ( obj.hasOwnProperty(p) ) {
                               if( obj[p] !== null && typeof(obj[p]) === "object" ) {
                                 new_obj[p] = clone( obj[p] );
                               }
                               else {
                                 new_obj[p] = obj[p];
                               }
                             }
                           }

                           return new_obj;
                         };


/* Example */
var foo = {
     name:  "Foo"
   , email: "bar@baz.com"
   , obj:   {a:"A",b:"B"}
};

var bar   = foo.clone();
bar.name  = "Bar";
bar.obj.b = "C";


// foo and bar should have a different 'name'
// foo and bar should retain the same email
// foo and bar should have different values for <foo/bar>['obj']['b']
// foo and bar should have the same values for <foo/bar>['obj']['a']
console.dir(foo);
console.dir(bar);
vol7ron
  • 40,809
  • 21
  • 119
  • 172
  • 3
    no no no... never mess with Object.prototype, you'll break everything :P – Dagg Nabbit Sep 22 '10 at 23:38
  • 2
    that is incorrect, unless you're one of the drones that use `JQuery`, then never mess with anything and forget how to do anything. – vol7ron Sep 22 '10 at 23:46
  • 2
    Don't get upset. I generally avoid jQuery. Two things, though... 1, this isn't a clone, it's a copy. The name 'cloning' is associated with this sort of technique: http://oranlooney.com/functional-javascript/ – Dagg Nabbit Sep 22 '10 at 23:52
  • 5
    2, don't mess with built-ins like Object and Array, not because of jQuery, but because someone will forget to use hasOwnProperty when iterating objects using `in` and suddenly they'll have extra properties in there, because another developer modified built-ins without them knowing. – Dagg Nabbit Sep 22 '10 at 23:54
  • 2
    [@no:](http://stackoverflow.com/users/331032/no) You make a valid point to remember, but I do not consider that good enough to essentially say "don't mess with prototype". – vol7ron Sep 23 '10 at 00:11
  • @no: nope, wrong again. you're batting 0 – vol7ron Sep 23 '10 at 00:25
  • 1
    All negatives and yet this is still the best answer. – vol7ron Sep 23 '10 at 05:14
  • Your code will give incorrect results when cloning `null` since `typeof(null) === "object`! Use `if(a[p] !== null && typeof(a[p])==="object")` instead... (Also it will break in IE if I remember correctly) – ntninja Aug 21 '14 at 14:23
  • 1
    @alexander255 I think you're right and there's probably a lot that can be done to improve this; especially since it's been 5 years since this answer has been submitted :) When I have a sec I'll try to update, if not, I hope someone reads the commetns – vol7ron May 31 '15 at 19:46
  • My younger self sounds like a jerk, but the simple fact of the matter is that Polyfills and Shims exist by using `prototype` on core objects to provide functionality that either exists in other browsers or to provide functionality that should exist natively by browsers (or ECMA language), for instance a *deep copy* or a *clone* method. In place of `in`, these days I prefer to use `Object.keys(obj)` to get the non-prototype keys of the object. It's personal preference, but easier to follow code for the next person that has to maintain my work. – vol7ron Feb 19 '16 at 21:16