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: "[email protected]"
}

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

13
  • 3
    JavaScript object != JSON object. The example you provided is a JavaScript object literal; I updated your post accordingly. Commented Sep 22, 2010 at 22:16
  • good question! I'll always think that user2 = user will make a copy, but don't. Commented Sep 22, 2010 at 22:16
  • 1
    Shortest 'answer': yes and yes. ;) Commented Sep 22, 2010 at 22:24
  • The answer you selected is still not a deep copy..my solution is still the best. Commented Oct 10, 2010 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 !! Commented Feb 22, 2013 at 17:18

5 Answers 5

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: "[email protected]"
}

var clonedUser = clone(user);

console.dir(clonedUser);

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

Sign up to request clarification or add additional context in comments.

18 Comments

user={name:"",email:"",obj:{a:"A"}}; clonedUser=clone(user);, clonedUser.obj.a="B"; you'll find user.obj.a == "B"
This looks really similar to Chris J's answer too.
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.
@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.
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.
|
11

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

var user = {name: "Foo", email: "[email protected]" } 
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.

4 Comments

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.
I'm just giving another way to do this. If a site already have json2.js, it works.
If an object has both properties and methods, then my friend, using this JSON style, methods are not cloned
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!
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: "[email protected]"
};
var user2 = Object.create(user);

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

5 Comments

You shouldn't do this; see Kangax' answer
@Marcel Thanks for pointing that out. I'll leave my answer as is and recommend Kangax' explanation as a good read.
@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.
Would be good if Javascript could provide an easy way to clone objects
I like that one best of all.
2

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

var a= {'key':'value'};
var b= jQuery.extend( true, {}, a );

1 Comment

Agreed: underscorejs also has a clone method underscorejs.org/#clone
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: "[email protected]"
   , 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);

10 Comments

no no no... never mess with Object.prototype, you'll break everything :P
that is incorrect, unless you're one of the drones that use JQuery, then never mess with anything and forget how to do anything.
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: oranlooney.com/functional-javascript
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.
@no: You make a valid point to remember, but I do not consider that good enough to essentially say "don't mess with prototype".
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.