我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

首先,需要说明的是:在JavaScript/nodejs里面,并没有array.copy()或者array.clone()等方法。但是,有无数种替代方案,可以实现数组复制的需求。最终,还可以根据上述这些方案,选个简单的方案,通过prototype修改array类型的方法,凭空增加一个.copy()方法。

苏南大叔:JavaScript,数组复制的N种方案大全,谁是最优解? - 数组复制克隆方案大全
JavaScript,数组复制的N种方案大全,谁是最优解?(图5-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的编程经验文章。测试环境:chrome@131.0.6778.70nodejs@20.18.0

问题描述

对于数组复制克隆来说,a=b这种操作是必然不行的。因为两个变量会共用一个内存地址,改变一个变量的时候,两个变量会同时改变。例如:

var a = ["su", "大叔"];
var b = a;
a[0] = "苏南";
console.log(b);     // [ '苏南', '大叔' ]
console.log(a==b);  // true
console.log(a===b); // true

数组是否克隆成功判断

对于数组是否值相同这个需求判断来说,通过实践证明:==判断,或者===判断,都不能解决问题。参考文章:

_lodash这个非常有用的库里面,存在着一个_.isEqual的判断方法,能判断变量内容是否相等。但是,也不能完全解决问题。

import _ from "lodash";
var i = 0;
function test(a, b) {
  // console.log(a == b);
  // console.log(_.isEqual(a, b));
  i = i + 1;
  if (a !== b && _.isEqual(a, b)) {
    console.log(i + ",克隆成功");
    return true;
  }
  console.log(i + ",克隆【失败】");
  return false;
}

最终确定的方案是,克隆成功的标准,两者内容相同,但是不使用同一个内存地址。

a !== b && _.isEqual(a, b)

苏南大叔:JavaScript,数组复制的N种方案大全,谁是最优解? - 测试函数
JavaScript,数组复制的N种方案大全,谁是最优解?(图5-2)

测试对象

这里准备了两个测试变量,简单数组能通过考验,但是复杂的数组可不一定。

function getA() {
  // return ["a", "b"];  // 简单版
  return [
    "sunan",
    123,
    [
      true,
      { ok: true, nice: "very" },
      () => {
        console.log("a");
      },
    ],
  ];
}

推荐的方案

array相关的函数非常多,虽非主观注意,但是确实能够客观上产生克隆效果的函数,也有很多。

苏南大叔:JavaScript,数组复制的N种方案大全,谁是最优解? - 推荐的方案
JavaScript,数组复制的N种方案大全,谁是最优解?(图5-3)

方案一,.map

var a = getA();
var a1 = a.map((x) => x);
test(a1, a);

方案二,.filter

var a = getA();
var a2 = a.filter(() => true);
test(a2, a);

方案三,.slice

var a = getA();
var a3 = a.slice();
test(a3, a);

方案四,Array.from()

var a = getA();
var a4 = Array.from(a);
test(a4, a);

方案五,[...a] [推荐]

var a = getA();
var a5 = [...a];
test(a5, a);

方案六七八,.concat

var a = getA();
var a6 = a.concat();
var a7 = a.concat([]);
var a8 = [].concat(a);
test(a6, a);
test(a7, a);
test(a8, a);

方案九,Array.prototype.copy 【不是太推荐】

Array.prototype.copy = function () {
  return [...this];
};
var a = getA();
var a9 = a.copy();
test(a9, a);

修改原型链,可能会给其它方案带来困惑,可以参考下面的方案十的运行结果。

苏南大叔:JavaScript,数组复制的N种方案大全,谁是最优解? - 推荐的方案2
JavaScript,数组复制的N种方案大全,谁是最优解?(图5-4)

不推荐的方案

不推荐的理由有:
需要安装第三方库,或者不支持深层次拷贝,或者部分数据会丢失,或者表述相对复杂,或者不通用,只能在浏览器端或者纯node端使用。

苏南大叔:JavaScript,数组复制的N种方案大全,谁是最优解? - 不推荐的方案
JavaScript,数组复制的N种方案大全,谁是最优解?(图5-5)

方案十,extend【不推荐】

import extend from "extend";
var a = getA();
var a10 = extend(true, [], a);
test(a10, a);

方案十一,assign【不推荐】

连据说仅仅支持浅复制的Object.assign()都通过了测试。

var a = getA();
var a11 = Object.assign([], a);
test(a11, a);

方案十二,JSON【不推荐】

对于复杂对象,唯一失败的一种方案。简单的数组可以通过测试。复杂数组里面的匿名函数被转化丢了。

var a = getA();
var a12 = JSON.parse(JSON.stringify(a)); // 这个不靠谱,pass
test(a12, a);

方案十三,jquery【不推荐】

jquery在浏览器里面运行,在纯node环境下,就很尴尬了。

var a = getA();
var a13 = $.extend({},a);

相关链接

结语

这么多眼花缭乱的方案里面,苏南大叔印象最深刻的是[...a]。最近是和"三个点"各种偶遇啊...
更多苏南大叔的JavaScript的文章,请点击链接:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   js