3

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

5 回答 5

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
于 2012-06-27T17:04:24.457 回答
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

演示

于 2012-06-27T17:04:49.403 回答
1

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

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

var x = { 'name': 'my obj', 'colors': c };
var y = $.extend({}, x);
于 2012-06-27T17:04:54.917 回答
1

不,那是因为变量xy指向同一个对象。通过设置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);

thencopy[0]仍然会purple像现在一样指向colors[0]。您可能想使用该deep选项

var x = {name:'my obj', colors:[{purple: 1}, {red:2}]};
var y = $.extend(true, {}, x);
于 2012-06-27T17:07:54.067 回答
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"}}
于 2012-06-27T17:23:37.973 回答