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

时间:2022-07-26 21:16:10

In my Angular application, I have an array that refers to the coordinates of a polygon. Eg:

在我的Angular应用程序中,我有一个引用多边形坐标的数组。例如:

[[-1,0], [0,1], [1,0], [0,-1], [-1,0]]

[[-1,0],[0,1],[1,0],[0,-1],[ - 1,0]]

The important bit here is that the that the first and last points are repeated, and actually reference the same 2-length array. This is a result of a plugin I'm using. However, some times the arrays will be created in such a way that the first and last points, while having the same value, are not the same reference.

这里重要的是重复第一个和最后一个点,并实际引用相同的2长度数组。这是我正在使用的插件的结果。但是,有时会以这样的方式创建数组:第一个和最后一个点虽然具有相同的值,但它们不是相同的引用。

At a certain point in my Angular application, I need to create a new polygon with the same coordinates as the original, only flipped. My first attempt was this:

在我的Angular应用程序的某个点上,我需要创建一个与原始坐标相同的新多边形,只需要翻转。我的第一次尝试是这样的:

var newCoords = angular.copy(polygon.coordinates);
for (var i = 0; i < newCoords.length; i++) {
  newCoords[i].reverse();
}

However, in those instances in which the first and last coordinates have the same reference, I was ending up with one of the points being reversed twice.

但是,在第一个和最后一个坐标具有相同参考的情况下,我最终得到的一个点被反转两次。

My understanding was that angular.copy() creates a deep copy of whatever is passed in, and I shouldn't be experiencing this issue. Clearly this is incorrect, so why? Is there a way to do a truly deep copy of the coordinates array that eliminates that odd reference pairing? I've managed to get around it for now by adding in an additional angular.copy(newCoords[i]) before the reverse().

我的理解是angular.copy()创建了传入的任何内容的深层副本,我不应该遇到这个问题。显然这是不正确的,为什么呢?有没有办法做一个真正的坐标数组深度副本,消除奇怪的参考配对?我现在通过在reverse()之前添加一个额外的angular.copy(newCoords [i])来设法绕过它。

1 个解决方案

#1


1  

As suggesting in the comments, this is related to a change inside of angular's core. This change was released in Angular v1.2.17. The bug fix was listed as:

正如评论中所暗示的那样,这与角度核心内部的变化有关。此更改已在Angular v1.2.17中发布。错误修复列为:

angular.copy: support circular references in the value being copied (5c997209, #7618)

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

However, along with circular references, double references are also handled. To intentionally not handle the double references, you have a few options. Like you mentioned in your post, after preforming a copy, recopy the first index. Not particularly intuitive, but it will work fine in any case:

但是,除了循环引用外,还会处理双引用。要故意不处理双引用,您有几个选项。就像你在帖子中提到的那样,在预成型副本之后,重新复制第一个索引。不是特别直观,但它在任何情况下都可以正常工作:

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

Another option is just to use any Angular versions prior to v1.2.17 (even all the way back to v0.9.0), because their default behavior is to create two different clones for each reference.

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


For others that may need to do a deep copy, but do not know the exact location of which duplicate references are (and may even be in subobjects), there is another way that will work with Angular versions prior to v1.4.8. This is to pass a third argument into copy to disable circular reference handling. Note that this will work with all versions prior to v1.2.17 as well, because they will simply ignore the 3rd parameter and do their default behavior:

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

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

The third parameter is the undocumented stackSource. By overriding it's push method to do nothing, the circular reference detection is broken. Two important things to note is that cyclical references will error (like v1.2.16 and down), and this doesn't work in v1.4.8 and up due to a performance change. In those cases you would have to write your own deep copy function.

第三个参数是未记录的stackSource。通过覆盖它的推送方法什么都不做,循环参考检测被打破了。需要注意的两个重要事项是循环引用会出错(如v1.2.16和down),由于性能变化,这在v1.4.8及更高版本中不起作用。在这些情况下,您必须编写自己的深层复制功能。

#1


1  

As suggesting in the comments, this is related to a change inside of angular's core. This change was released in Angular v1.2.17. The bug fix was listed as:

正如评论中所暗示的那样,这与角度核心内部的变化有关。此更改已在Angular v1.2.17中发布。错误修复列为:

angular.copy: support circular references in the value being copied (5c997209, #7618)

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

However, along with circular references, double references are also handled. To intentionally not handle the double references, you have a few options. Like you mentioned in your post, after preforming a copy, recopy the first index. Not particularly intuitive, but it will work fine in any case:

但是,除了循环引用外,还会处理双引用。要故意不处理双引用,您有几个选项。就像你在帖子中提到的那样,在预成型副本之后,重新复制第一个索引。不是特别直观,但它在任何情况下都可以正常工作:

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

Another option is just to use any Angular versions prior to v1.2.17 (even all the way back to v0.9.0), because their default behavior is to create two different clones for each reference.

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


For others that may need to do a deep copy, but do not know the exact location of which duplicate references are (and may even be in subobjects), there is another way that will work with Angular versions prior to v1.4.8. This is to pass a third argument into copy to disable circular reference handling. Note that this will work with all versions prior to v1.2.17 as well, because they will simply ignore the 3rd parameter and do their default behavior:

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

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

The third parameter is the undocumented stackSource. By overriding it's push method to do nothing, the circular reference detection is broken. Two important things to note is that cyclical references will error (like v1.2.16 and down), and this doesn't work in v1.4.8 and up due to a performance change. In those cases you would have to write your own deep copy function.

第三个参数是未记录的stackSource。通过覆盖它的推送方法什么都不做,循环参考检测被打破了。需要注意的两个重要事项是循环引用会出错(如v1.2.16和down),由于性能变化,这在v1.4.8及更高版本中不起作用。在这些情况下,您必须编写自己的深层复制功能。