Angular.copy()不会对引用的数组进行深层复制

4
在我的Angular应用程序中,有一个数组,它是多边形坐标的引用。例如:
[[-1,0], [0,1], [1,0], [0,-1], [-1,0]]
重要的部分在于第一个和最后一个点被重复,并实际上引用了同一个2个长度的数组。这是我使用的插件的结果。然而,有时候数组将以这样的方式创建,即使第一个和最后一个点具有相同的值,但不是同一个引用。
在我的Angular应用程序的某个特定点上,我需要创建一个新的多边形,其坐标与原始多边形相同,只是翻转过来。我的第一次尝试是这样的:
var newCoords = angular.copy(polygon.coordinates);
for (var i = 0; i < newCoords.length; i++) {
  newCoords[i].reverse();
}

然而,在第一个和最后一个坐标引用相同的情况下,我最终得到了其中一个点被反转两次的结果。
我的理解是angular.copy()会创建所传递内容的深拷贝,因此不应该出现这种问题。显然这是错误的,那么原因是什么呢?有没有一种真正深度复制坐标数组的方法来消除奇怪的引用配对?目前,我已经通过在reverse()之前添加另一个angular.copy(newCoords[i])来解决这个问题。

你能重现这个问题吗?对我来说,使用相同的参考资料是有效的。你的情况是否类似于这个链接:http://jsfiddle.net/rahpuser/2ngtw4bw/2/? - rahpuser
这可能是我的应用程序版本的angular.copy()出现了错误。如果你在这里看一下(http://jsfiddle.net/2ngtw4bw/4/),它会按预期输出`false true false。但是当我将那段代码*完全*复制到我的应用程序中时,它会输出false true true`。 - Will Durney
实际上,这似乎是Angular 1.2.1(jsfiddle)和Angular 1.2.19(我的应用程序)之间的一个错误修复。这取决于您对深度复制定义是否包括在新对象中维护相对引用。angular.copy文档可能应该更清楚地说明这一点。 - Will Durney
你是对的,在jsfiddle中更改了Angular版本后,我得到了与你相同的结果:false true true。 - rahpuser
也许这与此相关(在1.3中引入):https://github.com/angular/angular.js/commit/b59b04f98a0b59eead53f6a53391ce1bbcbe9b57 - glepretre
1个回答

1

正如评论中所提到的,这与Angular核心内部的更改有关。这个更改已经在Angular v1.2.17中发布。修复的错误被列为:

angular.copy: 支持在被复制的值中的循环引用 (5c997209, #7618)

然而,除了循环引用之外,双重引用也被处理。如果想要故意不处理双重引用,你有几个选择。像你在帖子中提到的那样,在执行复制后,重新复制第一个索引。虽然不是特别直观,但在任何情况下都可以正常工作:

var newCoords = angular.copy(polygon.coordinates);
// Ensure unique reference for the first element
newCoords[0] = angular.copy(newCoords[0]);

另一个选择是使用任何Angular版本,但要在v1.2.17之前(甚至可以回溯到v0.9.0),因为它们的默认行为是为每个引用创建两个不同的克隆。

对于需要进行深拷贝但不知道确切重复引用位置(甚至可能在子对象中)的其他人,有另一种方法可在Angular v1.4.8之前的版本中使用。这是通过向copy传递第三个参数来禁用循环引用处理。请注意,这也适用于v1.2.17之前的所有版本,因为它们将简单地忽略第三个参数并执行默认行为:

var stackSource = angular.extend([], {push:angular.noop});
var newCoords = angular.copy(polygon.coordinates, null, noopArray);

第三个参数是未记录的 stackSource 堆栈源。通过重写它的push方法不做任何事情,破坏了循环引用检测。需要注意的两个重要事项是循环引用会出错(像v1.2.16及以下版本),而在v1.4.8及以上版本中由于性能改变而无法使用。在这些情况下,您需要编写自己的深度复制函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接