0

Couldn't find an answer dealing with cloning instantiated objects in JavaScript. What's the best way to clone an existing instantiated object? E.g.,

function Person() {
}

Person.prototype.setName = function(name) {
    this.name = name;
}

var person = new Person();
person.setName('Charles Xavier');

function cloneInstantiated(instantiatedObject) {
    var clone = ... new Person ... ????

    return clone;
}

var clone = cloneInstantiated(person);

console.log(clone.name); // Charles Xavier

if(clone !== person) {
    console.log('Success! We have cloned Charles Xavier into a different memory address.');
}
Kirk Ouimet
  • 27,280
  • 43
  • 127
  • 177
  • possible duplicate of [What is the most efficient way to clone an object?](http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-an-object) – svidgen Dec 09 '14 at 20:23
  • 1
    @svidgen There's a big difference between `Object` and *instantiated object*! – Tomáš Zato Dec 09 '14 at 20:27
  • @TomášZato *All* objects are "instantiated." If the concern is that the prototype is absent from the new object after using one of the widely used `clone()` functions, just add the prototype to the new object after the basic `clone()`. If the OP's concern is that his clone-method-of-choice doesn't also copy instance methods ... it's simple enough to loop and/or recurse through and add them. – svidgen Dec 09 '14 at 20:35
  • Often it's quite important that `clone instanceof Person` returns `true`. I don't see a point in "adding the prototype later" if you can *instantiate* object using `new` and then copy properties. – Tomáš Zato Dec 09 '14 at 20:40
  • is o2=Object.create(o) enough for your app? – dandavis Dec 09 '14 at 23:14

2 Answers2

2

There's no native or universal way as far as I know. I prefer to write .clone method for my pseudo classes and use it:

Person.prototype.clone = function() {
    var clone = new Person()
    clone.name = this.name;
}

You could loop through own properties of the object to clone them while not copying stuff inherited from other objects:

for(var i in this) {
   if(this.hasOwnProperty(i)) {
       clone[i] = this[i];
   }
}

This will copy everything that was added to your object after instantiating (eg. won't copy the prototype properties which were already added by calling new Person.

Object.getPrototypeOf

thanks to Bergi
This method allows you to retrieve the prototype of any object. So instead of new Name you can use:

var clone = Object.create(Object.getPrototypeOf(this))

That's an universal solution which can save you lot of work. You must then proceed with copying own properties using for(var i in ...).

Object.create (supported since node V8) (MDN)

Finally, you could create a person that inherits from the original object:

var clone = Object.create(this);

That can be useful in special cases, but normally I wouldn't recommend it.

.toSource (Node.js module) (MDN)

It's also interesting to know that you can (in certain browsers firefox only) override method .toSource which is defined for all objects, even the native ones:

toSource method

In certain cases, you might want to do:

Person.prototype.toSource = function() {
    //Assuming name can be given in constructor
    return "new Person("+this.name.toSource()+")";
}

Further reading

Aside from the linked docs, I found this nice article about javascript object inheritance:

Community
  • 1
  • 1
Tomáš Zato
  • 50,171
  • 52
  • 268
  • 778
  • 1
    I'd recomment to use `var clone = Object.create(Object.getPrototypeOf(this))` – Bergi Dec 10 '14 at 21:06
  • If you get the prototype you don't copy the objects own properties. However your's is a good way to create object of the same instance without typing the name directly. +1 :) – Tomáš Zato Dec 11 '14 at 06:50
  • I thought that was the initalisation code for the loop over the own properties in the snippet right above? – Bergi Dec 11 '14 at 06:54
  • Yeah. As I say, your's a good idea. I just wasn't sure you realise that loop is still necesary. I'll try to add your idea to my answer. Thank you. – Tomáš Zato Dec 11 '14 at 07:13
  • @Kirk Wasn't my answer sufficient? I've spent a lot of time with it and now it seems you didn't even read it. – Tomáš Zato Mar 06 '15 at 12:19
0

This works perfectly... Fiddle

function Person() {
}

Person.prototype.setName = function(name) {
    this.name = name;
}

var person = new Person();
person.setName('Charles Xavier');

function cloneInstantiated(instantiatedObject) {
    var clone = {};
    for (key in instantiatedObject) {
        clone[key] = instantiatedObject[key];
    }
    return clone;
}

var clone = cloneInstantiated(person);

console.log(clone.name); // Charles Xavier

if(clone !== person) {
    console.log('Success! We have cloned Charles Xavier into a different memory address.');
}
Ruchir Gupta
  • 990
  • 3
  • 10
  • 20
  • You've got uninitialised global variable in your code (`key`). Looping through all keys is really not necessary, usually you just need to copy the topmost layer of inheritance. – Tomáš Zato Dec 09 '14 at 20:34
  • 1
    What if one of the variables on the instance had captured a reference to the other object, or if a function was explicitly bound for instance? While it works for this specific case, this doesn't work as a generic solution. – loganfsmyth Dec 09 '14 at 21:12