Javascript使用$ .extend按值复制,但只是一个对象属性

时间:2012-06-27 16:59:10

标签: javascript jquery inheritance zepto

我正在尝试按值复制属性,以便不同的实例可以单独修改它。我的理解是使用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 );

5 个答案:

答案 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

DEMO

答案 2 :(得分:1)

这不是造成这种情况的副本,而是var x = y = {。您将y设置为对象,然后将x设置为y。这会导致xy指向同一个对象。

您需要将对象设置为其中一个变量,然后将其复制到另一个变量。

var x = { 'name': 'my obj', 'colors': c };
var y = $.extend({}, x);

答案 3 :(得分:1)

不,这是因为变量xy指向同一个对象。通过将y.colors设置为新值,您可以在访问x.colors时获得该值。 $.extend([],x.colors)是原始c的副本并不重要。

但如果xy是具有不同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"}}