Javascript 使用 $.extend 按值复制,但只有一个对象属性
Posted
技术标签:
【中文标题】Javascript 使用 $.extend 按值复制,但只有一个对象属性【英文标题】:Javascript copy by value using $.extend, but only an object property 【发布时间】:2012-06-29 04:35:43 【问题描述】:我正在尝试按值复制属性,以便不同的实例可以单独修改它。我的理解是,使用 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 );
【问题讨论】:
您有 2 个完全相同的对象 --var x = y =...
当您将对象分配给变量时。
【参考方案1】:
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
【讨论】:
完全正确 -- 不需要扩展为 x = y 对不起,这个例子很糟糕。这些对象是相同的引用,但是因为它们是作为函数参数传递的。澄清示例... @SimpleAsCouldBe 是的,但是深拷贝仍然可以解决这个问题(在您的示例代码中,x 和 y 是不同的对象,但它们包含的数组仍然是一个单独的数组 - 它们都包含一个引用到它,所以你需要一个深拷贝来确保它是按值复制的):jsfiddle.net/n6fzV @Niko:所以没有深拷贝它仍然会复制属性,但只能通过引用?我认为它会留下深刻的东西未定义。参考可以解释一切。 @SimpleAsCouldBe 是的,浅拷贝将所有内容从 A 复制到 B,但如果 A 包含对对象的引用(例如数组),它只会复制引用。深拷贝还对 A 中的对象以及这些对象中的对象等进行真实拷贝。【参考方案2】:你想要这样的东西:
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
DEMO
【讨论】:
当我在 firebug 控制台中尝试时,您的代码中有一些错误:with(_FirebugCommandLine) var c = [ 'purple' : 1, 'red':2 ] var x = '名称': '我的 obj', '颜色': 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 );​ ;【参考方案3】:造成这种情况的不是副本,而是var x = y =
。您将y
设置为一个对象,然后将x
设置为y
。这会导致x
和y
指向同一个对象。
您需要将对象设置为其中一个变量,然后将其复制到另一个。
var x = 'name': 'my obj', 'colors': c ;
var y = $.extend(, x);
【讨论】:
对象在实际用例中通过函数传递,因此它们确实相互引用。我会澄清这个例子。【参考方案4】:不,这是因为变量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]
仍然会像colors[0]
一样指向purple
。您可能想使用deep
option:
var x = name:'my obj', colors:[purple: 1, red:2];
var y = $.extend(true, , x);
【讨论】:
【参考方案5】:$.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"
【讨论】:
以上是关于Javascript 使用 $.extend 按值复制,但只有一个对象属性的主要内容,如果未能解决你的问题,请参考以下文章