【问题标题】:Angular.copy() not deep copying referenced arraysAngular.copy() 不是深度复制引用的数组
【发布时间】:2015-01-22 07:19:08
【问题描述】:

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

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

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

在我的 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]) 来解决它。

【问题讨论】:

  • 你能重现这个问题吗?对我来说,我正在使用相同的参考资料,你有这样的东西吗? jsfiddle.net/rahpuser/2ngtw4bw/2
  • 在我的应用程序的 angular 版本中一定是 angular.copy() 的错误。如果您看这里 (jsfiddle.net/2ngtw4bw/4),则会按预期打印出 false true false。当我将该代码完全复制到我的应用程序中时,它会打印出false true true
  • 实际上,这似乎是 Angular 1.2.1(jsfiddle)和 Angular 1.2.19(我的应用程序)之间的错误 fix。这取决于您对深拷贝的定义是否包括在新对象中维护相对引用。 angular.copy 文档可能会更清楚地说明这一点。
  • 你是对的,在 jsfiddle 中更改 angular 版本后,我得到的结果与你相同:false true true..
  • 也许这可能是相关的(在 1.3 中引入):github.com/angular/angular.js/commit/…

标签: javascript angularjs reference deep-copy shallow-copy


【解决方案1】:

正如 cmets 中所暗示的,这与 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 之前的所有版本,因为它们将简单地忽略第三个参数并执行其默认行为:

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

第三个参数是未记录 stackSource。通过重写它的 push 方法什么都不做,循环引用检测被破坏了。需要注意的两件事是循环引用会出错(如 v1.2.16 及以下版本),由于性能变化,这在 v1.4.8 及以上版本中不起作用。在这些情况下,您将不得不编写自己的深拷贝函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-08
    • 2014-11-03
    • 1970-01-01
    • 1970-01-01
    • 2020-07-28
    • 1970-01-01
    • 2010-09-30
    • 1970-01-01
    相关资源
    最近更新 更多