16

jsFiddle here.

If deep copying worked, the output would be "Curious George" and not "Ender's Game". How can I make a deep copy? An answer to this question indicates that $.extend(true, [], obj) creates a deep copy. Yet my example shows that it doesn't.

function Person(){}
Person.prototype.favorite_books = [];

var george = new Person();
george.favorite_books = ["Curious George"];

var kate = new Person();
kate.favorite_books = ["The Da Vinci Code", "Harry Potter"];

var people = [kate, george];

var people_copy = $.extend(true, [], people);
people_copy[0].favorite_books[0] = "Ender's Game";

$('#text').text(people[0].favorite_books[0]);

SOLUTION

I updated the jsFiddle. It turns out I need to deep copy each object in the array individually if the object is a custom object (that is, $.isPlainObject returns false).

7
  • use .clone() see api.jquery.com/clone Commented May 12, 2013 at 22:44
  • 6
    @Paul Sullivan: .clone() is to be used with DOM entities Commented May 12, 2013 at 22:44
  • okay so browse .extend source code and see why the recursive function isn't copying attributes Commented May 12, 2013 at 22:45
  • 2
    @karthikr: have you even read this question and the answer you've referred? Commented May 12, 2013 at 22:49
  • 1
    "It turns out I need to deep copy each object in the array individually." ... if only you're custom objects Commented May 12, 2013 at 23:06

3 Answers 3

21

And now here is the real answer:

At the moment jQuery can only clone plain JavaScript Objects, while you're using custom ones. And that's obvious, since jQuery cannot know how exactly to instantiate a new custom object. So this works as expected:

var george = {};
george.favorite_books = ["Curious George"];

var kate = {};
kate.favorite_books = ["The Da Vinci Code", "Harry Potter"];

var people = [kate, george];

var people_copy = $.extend(true, [], people);

console.log(people_copy[0].favorite_books == people[0].favorite_books);

Reference to a jQuery code: https://github.com/jquery/jquery/blob/master/src/core.js#L305

See that it checks if it's jQuery.isPlainObject(copy) or it's an array. Otherwise it performs just a reference copy.

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

3 Comments

@Rose Perrone: because you have created a deep copy. So the original object is kept as is, and the modified one is modified independently. Not sure what is confusing you.
@RoyiNamir you specified that it should be a deep copy (the first argument)
Please check what first boolean argument in $.extend function call means. And ask another question if it's still not clear for you.
9

This is how I've done it after trying many approaches:

var newArray = JSON.parse(JSON.stringify(orgArray));

This will create a new deep copy, not a shallow copy.

Also this obviously will not clone events and functions, but the good thing is you can do it in one line, and it can be used for any king of object (arrays, strings, numbers, objects, etc.).

Comments

4

Interesting....it doesn't look like it deep copies arrays.

You have to deep copy each object individually.

var people_copy = [];
$.each(people,function(i,obj) {
    people_copy.push($.extend(true,{},obj)); 
});

EDIT: Sure, look at this fork of the OP's fiddle:

http://jsfiddle.net/s2bLv/4/

3 Comments

"deep copies objects, not arrays" --- any proofs for that? Isn't array a special kind of object?
If you have to deep copy each object individually you would need some recursive code to copy all the way down - unless this is only supposed to cover the OP's simple test case rather than being a generic solution?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.