zl程序教程

您现在的位置是:首页 >  前端

当前栏目

JavaScript中合并数组的N种方法

2023-06-13 09:15:45 时间

这是一篇简单的文章,关于JavaScript数组使用的一些技巧。我们将使用不同的方法结合/合并两个JS数组,以及讨论每个方法的优点/缺点。

让我们先考虑下面这情况:

复制代码代码如下:

vara=[1,2,3,4,5,6,7,8,9];
varb=["foo","bar","baz","bam","bun","fun"];

很显然最简单的结合结果应该是:
复制代码代码如下:

[
  1,2,3,4,5,6,7,8,9,
  "foo","bar","baz","bam""bun","fun"
]

concat(..)

这是最常见的做法:

复制代码代码如下:
varc=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"就被回收了

呵呵。对于只有几个元素的小数组,这没啥问题。但对于大数组,或者在内存有限的系统中需要经常重复这个过程,它其实还有很多改进的地方。

循环插入

好吧,让我们将一个数组的内容复制到另一个,使用:Array#push(..)

复制代码代码如下:
//`b`onto`a`
for(vari=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(vari=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"]

功能技巧

不过for循环确实比较丑,而且不好维护。我们可以做的更好吗?

这是我们的第一次尝试,使用Array#reduce:

复制代码代码如下:
//`b`onto`a`:
a=b.reduce(function(coll,item){
   coll.push(item);
   returncoll;
},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);
   returncoll;
},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的spead操作会更漂亮:a.push(...b)或b.unshift(...a

数组最大长度限制

第一个主要的问题是,内存使用量增长了一倍(当然只是暂时的!)被追加内容基本上是通过函数调用将元素复制到堆栈中。此外,不同的JS引擎都有拷贝数据长度的限制。
所以,如果数组有一百万个元素,你肯定会超出了push(...)或unshift(...)允许调用堆栈的限制。唉,处理几千个元素它会做得很好,但你必须要小心,不能超过合理的长度限值。

注意:你可以尝试一下splice(...),它跟push(...)和unshift(...)一样都有这种问题。

有一种方法可以避免这种最大长度限制。

复制代码代码如下:
functioncombineInto(a,b){
   varlen=a.length;
   for(vari=0;i<len;i=i+5000){
       b.unshift.apply(b,a.slice(i,i+5000));
   }
}

等一下,我们的可读性倒退了。就这样吧,可能会越改越差,呵。