创建多维数组的副本,而不是引用 - JavaScript

IT技术 javascript arrays copy
2021-02-06 08:24:47

这也被称为“深度复制”,我已经找到了一些关于它的文章。最接近的似乎是这个,但它是针对 jQuery 的——我试图在没有库的情况下做到这一点。

我还在两个地方看到可以执行以下操作:

arr2 = JSON.decode(JSON.encode(arr1));

但这显然是低效的。也可以单独循环和复制每个值,并在所有数组中递归。这似乎也很累人,效率也很低。

那么复制 JavaScript 多维数组的最有效的非库方式是[[a],[b],[c]]什么?如有必要,我对“非 IE”方法非常满意。

谢谢!

4个回答

由于听起来您正在处理某个未知深度级别的数组数组,但您只需要在任何给定时间在一个深度级别处理它们,那么使用起来就会简单快捷.slice()

var newArray = [];

for (var i = 0; i < currentArray.length; i++)
    newArray[i] = currentArray[i].slice();

或者使用.map()代替for循环:

var newArray = currentArray.map(function(arr) {
    return arr.slice();
});

所以这将迭代当前数组,并构建一个新的嵌套数组的浅拷贝数组。然后当你进入下一个深度时,你会做同样的事情。

当然,如果混合了数组和其他数据,您将需要在切片之前测试它是什么。

现在你可以做 es6 速记,使它更加简洁。 var newArray = currentArray.map(arr => arr.slice());
2021-03-15 08:24:47
我猜在大多数浏览器中,带有额外函数调用的映射要慢得多,尽管它可以通过内联进行优化,然后可能会表现得更好。
2021-03-16 08:24:47
@Bergi:是的,地图版本会受到一点影响,但很好很干净。
2021-03-22 08:24:47
目前我们只需要调用.slice(0)来克隆一个数组。使用没问题.slice(),但.slice(0)速度更快。
2021-04-04 08:24:47
哇,地图真干净
2021-04-13 08:24:47

我不确定JSON.stringifyandJSON.parseencodeand好多少decode,但你可以尝试:

JSON.parse(JSON.stringify(array));

我发现的其他东西(虽然我会稍微修改一下):

http://www.xenoveritas.org/blog/xeno/the-correct-way-to-clone-javascript-arrays

function deepCopy(obj) {
  if (typeof obj == 'object') {
    if (isArray(obj)) {
      var l = obj.length;
      var r = new Array(l);
      for (var i = 0; i < l; i++) {
        r[i] = deepCopy(obj[i]);
      }
      return r;
    } else {
      var r = {};
      r.prototype = obj.prototype;
      for (var k in obj) {
        r[k] = deepCopy(obj[k]);
      }
      return r;
    }
  }
  return obj;
}
这两种方法的缺点是它们不处理自引用循环——这可能重要也可能不重要(不确定 JSON 版本将如何处理它,但第二个示例将无限循环)
2021-03-31 08:24:47
什么是r.prototype = obj.prototype;应该做的?对我来说似乎很不对
2021-04-03 08:24:47
@Jeff 我相信你,但你能举一个(小)例子吗?只是想了解
2021-04-04 08:24:47
var x = {}; x.y = x;else每次deepCopy调用都会命中该语句,而 JSON 无法处理自引用 - 它天生是基于树的
2021-04-04 08:24:47
@RandyHall, Jeff:不,不是。它只是创建了一个名为prototype. 这不会设置继承,就像__proto__会做的那样。正确的方法:Object.create(Object.getPrototypeOf(obj));如@Danny 的回答
2021-04-07 08:24:47

当您要求性能时,我想您也会采用非通用解决方案。要复制具有已知级别数的多维数组,您应该使用最简单的解决方案,一些嵌套的 for 循环。对于您的二维数组,它看起来就像这样:

var len = arr.length,
    copy = new Array(len); // boost in Safari
for (var i=0; i<len; ++i)
    copy[i] = arr[i].slice(0);

要扩展到高维数组,请使用递归或嵌套 for 循环!

本机slice方法比自定义 for 循环更有效,但它不会创建深度副本,因此我们只能在最低级别使用它。

任何不会两次访问同一个节点的递归算法都将与使用 javascript 获得的效率差不多(至少在浏览器中) - 在其他语言的某些情况下,您可能会复制大量内存,但 javascript 显然不会没有那个能力

我建议找一个已经完成它的人并使用他们的实现来确保你做对了——它只需要定义一次。