Angular.copy() 不是深度复制引用的数组

Angular.copy() not deep copying referenced arrays

本文关键字:复制 引用 数组 深度 copy Angular      更新时间:2023-09-26

在我的 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])来设法绕过它。

正如评论中所暗示的那样,这与 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]);

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


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

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

第三个参数是未记录stackSource。通过重写它的推送方法而不执行任何操作,循环引用检测被破坏。需要注意的两件重要事情是循环引用会出错(如 v1.2.16 及更低版本),由于性能变化,这在 v1.4.8 及更高版本中不起作用。在这些情况下,您必须编写自己的深拷贝函数。