JavaScript数组合并的多种方法:从concat到性能优化
本文深入探讨JavaScript中合并数组的多种实现方式,包括concat、循环push/unshift、reduce以及apply技巧。重点分析各方法在内存占用、执行效率及调用栈限制方面的差异,特别是针对大数组合并时的性能瓶颈与解决方案,帮助开发者根据实际场景选择最优策略。
JavaScript数组合并概述
本文简要介绍JavaScript数组操作的一些实用技巧,重点展示如何结合或合并两个JS数组,并逐一分析每种方法的优缺点。
首先设定一个基础场景:
var a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
var b = [ "foo", "bar", "baz", "bam", "bun", "fun" ];
预期的合并结果显而易见:
[
1, 2, 3, 4, 5, 6, 7, 8, 9,
"foo", "bar", "baz", "bam" "bun", "fun"
]
使用concat方法合并
concat(..)
这是最通用的合并手段:
var c = a.concat( b );
a; // [1,2,3,4,5,6,7,8,9]
b; // ["foo","bar","baz","bam","bun","fun"]
c; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]
如上所示,C生成了一个包含A和B元素的全新数组,而A和B保持不变。操作非常直观。
然而,如果数组A包含10,000个元素,数组B也有一万个元素,那么结果数组C将拥有2万个元素,导致A和B的内存占用暂时翻倍。
有人可能会说:‘没问题!’,建议将A和B设置为null以触发垃圾回收,从而释放内存。
a = b = null; // 'a'和'b'就被回收了 对于元素数量较少的小数组,这种做法尚可接受。但在处理大数组,或在内存受限环境中需要频繁执行此类操作时,仍有优化空间。
循环插入与内存优化
循环插入
接下来,尝试通过循环将数组B的内容逐个复制到数组A中,使用Array#push(..)方法:
// `b` onto `a`
for (var i=0; i < b.length; i++) {
a.push( b[i] );
}
a; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]
b = null;
此时,数组A已包含数组B的所有内容。
从内存占用的角度看,这种方法似乎更为经济。
但如果数组A较小呢?出于内存和速度的考虑,你可能希望将较小的数组A插入到数组B的前面。只需将push(..)替换为unshift(..)即可:
// `a` into `b`:
for (var i=a.length-1; i >= 0; i--) {
b.unshift( a[i] );
}
b; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]
函数式技巧与ES6展开操作
功能技巧
尽管for循环可行,但其代码可读性较差且不易维护。我们能否找到更优雅的解决方案?
第一次尝试是使用Array#reduce:
// `b` onto `a`:
a = b.reduce( function(coll,item){
coll.push( item );
return coll;
}, a );
a; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]
// or `a` into `b`:
b = a.reduceRight( function(coll,item){
coll.unshift( item );
return coll;
}, b );
b; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]
Array#reduce(..)和Array#reduceRight(..)虽然功能强大,但略显繁琐。ES6的箭头函数能减少部分代码量,但仍需为每个元素调用一次函数,并非最完美的方案。
那么试试这种方式:
// `b` onto `a`:
a.push.apply( a, b );
a; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]
// or `a` into `b`:
b.unshift.apply( b, a );
b; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]
这显然更加简洁。特别是当使用unshift(..)时,无需担心元素顺序反转的问题。ES6的展开操作符使代码更加美观:a.push( …b ) 或 b.unshift( …a )。
处理大数组的长度限制
数组最大长度限制
上述方法面临的一个主要问题是内存使用量会暂时翻倍(尽管是暂时的!)。被追加的内容本质上是通过函数调用将元素复制到调用栈中。此外,不同的JS引擎对拷贝数据的长度有限制。
因此,如果数组包含一百万个元素,你肯定会超出push(…)或unshift(…)允许的调用栈限制。虽然处理几千个元素时表现良好,但必须小心不要超过合理的长度限制。
注意:你可以尝试一下splice(…),它跟push(…)和unshift(…)一样都有这种问题。
有一种方法可以避免这种最大长度限制。
function combineInto(a,b) {
var len = a.length;
for (var i=0; i < len; i=i+5000) {
b.unshift.apply( b, a.slice( i, i+5000 ) );
}
}
然而,这样做的可读性反而下降了,甚至可能越改越复杂。
以上就是本文的全部内容,希望对大家学习javascript程序设计有所帮助。
配置 Matter.js 睡眠机制以优化静止物体性能
2026-11-05 15:43:12
JavaScript console.log高级用法:用table、group和time优化调试输出
2026-11-05 08:04:56
JS变量中存储HTML代码时的特殊字符转义方法
2026-11-04 19:04:09
JS怎么安全转换带千分位或货币符号的字符串为数字
2026-11-04 11:54:14
推荐几款稳定的在线JS反混淆工具,支持Obfuscator.io解密
2026-11-04 08:16:21
