我正在尝试按值复制属性,以便不同的实例可以单独修改它。我的理解是使用jQuery或Zepto的$ .extend是一种“按值复制”的好方法。它不适用于我的情况,我想了解原因。我不知道我做错了什么。
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
我觉得我可能会遗漏一些非常重要的东西。我可以不从同一个对象扩展来复制吗?关于函数参数范围有什么混淆吗?
jsFiddle:http://jsfiddle.net/zfnyp/5/
编辑:正如@Niko所指出的那样,我的困惑的答案是,深层拷贝会生成所有子属性的按值复制版本。我认为深度和浅拷贝只是意味着副本有多少属性。糟糕。再次编辑:深层复制在Javascript中很麻烦。 JQuery有它,但Zepto和Underscore没有。有人形容它不可能很好地实施。为了解决我的问题,我创建了这个解决方案,它依赖于了解对象的结构。我相信这对我来说是正确的答案,尽管它很笨重。
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 );
答案 0 :(得分:4)
x = y
使x和y引用相同的对象,因此y.colors
也会覆盖x.colors
- $.extend()
在这种情况下毫无用处。
var x = { 'name': 'my obj', 'colors': c };
var y = $.extend(true, {}, x); // <-- first param "true" = make deep copy,
// because otherwise "x.colors === y.colors"
深拷贝是必需的,因为数组也是一个对象,因此在执行浅拷贝时通过引用进行复制。
或使用新代码:
var inY = $.extend(true, {}, passX); // deep copy = also copy mod.colors by value
答案 1 :(得分:1)
你想要这样的东西:
var c = [ {'purple' : 1}, { 'red':2 } ]
var x = { 'name': 'my obj', 'colors': c };
var y = { 'name': 'my obj', 'colors': c };
y.colors = $.extend([],x.colors);
x.colors[0].selected = true;
console.log( x.colors[0].selected ); // true
console.log( y.colors[0].selected ); // now it's an error because y.colors[0] is undefined
答案 2 :(得分:1)
这不是造成这种情况的副本,而是var x = y = {
。您将y
设置为对象,然后将x
设置为y
。这会导致x
和y
指向同一个对象。
您需要将对象设置为其中一个变量,然后将其复制到另一个变量。
var x = { 'name': 'my obj', 'colors': c };
var y = $.extend({}, x);
答案 3 :(得分:1)
不,这是因为变量x
和y
指向同一个对象。通过将y.colors
设置为新值,您可以在访问x.colors
时获得该值。 $.extend([],x.colors)
是原始c
的副本并不重要。
但如果x
和y
是具有不同colors
数组的不同对象,它甚至无效。使用
var purple = {purple: 1}, red = {red: 2};
var colors = [purple, red];
var copy = $.extend([], colors);
然后copy[0]
仍然指向purple
,就像colors[0]
一样。您可能想要使用deep
option:
var x = {name:'my obj', colors:[{purple: 1}, {red:2}]};
var y = $.extend(true, {}, x);
答案 4 :(得分:0)
方法$.extend
可以执行深层复制。您所要做的就是在第一个位置添加一个新参数true
- 它标记深层复制模式 - 并将其余参数右移。
var o1 = {"a": "AA", "n": 11, "o": {"k0": "v0", "k1": "v1"}};
var oz = $.extend(true, {}, o1)
oz.o.k0 = 99;
dump(o1); // {a:"AA", n:99, o:{k0:"v0", k1:"v1"}}
dump(oz); // {a:"AA", n:99, o:{k0:99, k1:"v1"}}