JavaScript,数组复制的N种方案大全,谁是最优解?
发布于 作者:苏南大叔 来源:程序如此灵动~首先,需要说明的是:在JavaScript
/nodejs
里面,并没有array.copy()
或者array.clone()
等方法。但是,有无数种替代方案,可以实现数组复制的需求。最终,还可以根据上述这些方案,选个简单的方案,通过prototype
修改array
类型的方法,凭空增加一个.copy()
方法。
苏南大叔的“程序如此灵动”博客,记录苏南大叔的编程经验文章。测试环境:chrome@131.0.6778.70
,nodejs@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)
测试对象
这里准备了两个测试变量,简单数组能通过考验,但是复杂的数组可不一定。
function getA() {
// return ["a", "b"]; // 简单版
return [
"sunan",
123,
[
true,
{ ok: true, nice: "very" },
() => {
console.log("a");
},
],
];
}
推荐的方案
array
相关的函数非常多,虽非主观注意,但是确实能够客观上产生克隆效果的函数,也有很多。
方案一,.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);
修改原型链,可能会给其它方案带来困惑,可以参考下面的方案十的运行结果。
不推荐的方案
不推荐的理由有:
需要安装第三方库,或者不支持深层次拷贝,或者部分数据会丢失,或者表述相对复杂,或者不通用,只能在浏览器端或者纯node
端使用。
方案十,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);
相关链接
- https://newsn.net/say/js-proxy-array.html
- https://newsn.net/say/ndarray-equal.html
- https://newsn.net/say/js-splice.html
- https://newsn.net/say/js-array-map.html
- https://newsn.net/say/php-array-clone.html
结语
这么多眼花缭乱的方案里面,苏南大叔印象最深刻的是[...a]
。最近是和"三个点"各种偶遇啊...
更多苏南大叔的JavaScript
的文章,请点击链接:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。