Sign up ×
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other. Join them; it only takes a minute:

Introduction

I have a Class Persons that contains an array of Person and functions :

function Persons() {
  this.mItems = []; // Array of Objects Person
}

Persons.prototype = {
  calculateScores : function() {
    // Do some stuff
  }
}

The Class Person has members and functions :

function Person(name) {
  this.name = name; // Name of the Person
  this.score = 0;
}

Person.prototype = {
  calculateScore : function() {
    // Do some stuff
  }
}

I want that the program does the following things :

var persons = new Persons();
var person0 = new Person("John");
var person1 = new Person("Sam");
persons.mItems.push(person0);
persons.mItems.push(person1);

// Completely clone the original Objects
clonedPersons = persons.clone(); // I am looking for a clone() function

// Modify an item in the cloned Objects
clonedPersons.mItems[0].name = "Mick";

// Check that the original Objects have not been modified
console.log(persons.mItems[0].name); // John : Not modified
console.log(clonedPersons.mItems[0].name); // Mick

Question

I want to deep copy an instance of Persons to completely duplicate the Array of Person. The Objects Person must be duplicated. The functions of the Objects must be kept.

JQuery.extend()

JQuery.extend(true, {}, persons) clones the direct members of Persons but shallow copies the Person Objects.

console.log(persons.mItems[0].name); // Mick : Where is John ?!
console.log(clonedPersons.mItems[0].name); // Mick

JSON.parse(json.stringify())

clonedPersons = JSON.parse(json.stringify(persons)) clones the Objects but remove the functions.

persons.mItems[0].calculateScore(); // Does not exists !!!

Thank you for your answers.

share|improve this question
2  
Did you look at stackoverflow.com/questions/122102/… – mccainz Jul 15 at 15:49
    
Yes, but var newObject = jQuery.extend(true, {}, oldObject); does not deep copies the objects in the Array. – Samuel Jul 15 at 15:51
    
You're not asking about how to clone objects that contain arrays, but about how to clone class instances. – Bergi Jul 15 at 17:08
    
@Bergi : Is it not the same ? Objects are Class instances ? – Samuel Jul 15 at 20:27
1  
@Samuel: Usually we distinguish "plain" objects and arrays, which both are native "data types", from objects with custom prototypes that are created from user-defined constructors ("classes"). As you have seen, most deep-clone function support the former but not the latter. – Bergi Jul 15 at 20:30
up vote 3 down vote accepted

If you're dealing with custom classes, you're going to want to implement custom clone methods. Generally, in this context, I'd have 2 separate clone functions, one on the Person model and one on the Persons collection.

Persons.prototype = {
  clone: function() {
    var clone = new Persons();
    clone.mItems = this.mItems.map(function(person) {
        return person.clone();
    });
    return clone;
  }
}

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

The advantage to this approach is that it separates the concerns - the Person class doesn't have to know how to clone a single Person, it only has to know that Person exposes a clone method. If Person adds a new property that should be persisted in the clone, only Person needs to change.

It's generally an anti-pattern to use generic clone methods, e.g. from jQuery or Underscore, in this context. They'll end up cloning things you don't want, or missing things you do (e.g. a Person might eventually have an Address or some other object that will also need cloning).

share|improve this answer
    
OK for Old School clone(). Thanks ! – Samuel Jul 15 at 21:47

You can use [].map and Object.assign:

Persons.prototype.clone = function() {
   var clone = new Persons();
   clone.mItems = this.mItems.map(function(person) {
     return Object.assign(new Person, person);
   });
   return clone;
};
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.