I am trying to copy a property by value so that different instances can modify it separately. My understanding is that using jQuery or Zepto's $.extend is a great way to do 'copy by value'. It is not working in my situation and I'd like to understand why. I can't tell what I'm doing wrong.
var c = [ {'purple' : 1}, { 'red':2 } ]
var x = { 'name': 'my obj', 'colors': c }
var doWork = function(passX) {
var inY = $.extend({},passX);
inY.colors[0].selected = true;
return inY;
}
var y = doWork(x);
console.log( x.colors[0].selected );// true, but I think it should be undefined
console.log( y.colors[0].selected );// true
I feel like I might be missing something really central. Can I not extend from the same object to do a copy? Is there something confounding about the function argument scope?
jsFiddle: http://jsfiddle.net/zfnyp/5/
EDIT: The answer to my confusion, as @Niko points out, is that deep copy makes copy-by-value versions of all child properties. I thought deep vs shallow copy just meant how many properties deep the copy went. Oops.
EDIT AGAIN: Deep copy is troublesome in Javascript. JQuery has it, but Zepto and Underscore do not. Some describe it as impossible to implement well. To implement this for my problem, I have created this solution which relies on knowing the structure of the object. I believe this is the correct answer for me, though it is clunky.
var c = [ {'purple' : 1, 'selected':false }, { 'red':2 } ]
var x = { 'name': 'my obj', 'colors': c }
var doWork = function(passX) {
var inY = $.extend({},passX);
inY.colors = $.extend([], passX.colors);
for (var i = 0; i < passX.colors.length; i++) {
inY.colors[i] = $.extend({}, passX.colors[i]);
}
inY.colors[0].selected = true;
return inY;
}
var y = doWork(x);
console.log( x.colors[0].selected );
console.log( y.colors[0].selected );
x = y
makes x and y reference the same object, therefore y.colors
also overwrites x.colors
- the $.extend()
is pretty useless in this case.
var x = { 'name': 'my obj', 'colors': c };
var y = $.extend(true, {}, x); // <-- first param "true" = make deep copy,
// because otherwise "x.colors === y.colors"
The deep copy is required, because an array is also an object and therefore copied by reference when doing a shallow copy.
Or with the new code:
var inY = $.extend(true, {}, passX); // deep copy = also copy mod.colors by value