合规国际互联网加速 OSASE为企业客户提供高速稳定SD-WAN国际加速解决方案。 广告
# 数组合并 ## 前言 当面试官问你如何用js做数组合并,不要想当然的回答用`concat`方法。这是不合格的。面试官想听的是多种的方法以及分析其优劣,下面将列出js数组合并的方法并分析优劣 ## concat方法 这是最常见的用法。例如有这样一个数组 <pre>var a = [1,2,3,4,5] var b =['a', 'b','c','d','e'] </pre> 拼接出来的结果是 `var c = a.concat(b) //[1, 2, 3, 4, 5, "a", "b", "c", "d", "e"]` concat会返回一个<b>全新的数组</b>c, 不会改变`a`和`b`数组,但他们已经没用了。 现在深入解析concat方法的问题。 如果数组`a`和`b` 都有10000个以上元素。 那么c就有20000个以上元素,这种方式占用了2倍的内存 如果你说将 数组`a`,`b`空置等待垃圾回收不就可以了吗 `a = b = null` 但如果是小数组,那自然没问题,但对大型数组或者需要多次重复处理时,内存就被限制了。还需要进行优化。 ## 循环插入 可以把一个数组加入到另外一个数组中,使用Array.push() <pre>//将数组b插入到a中 for(var i = 0; i < b.length; i++) { a.push(b[i]) } b = null a //[1, 2, 3, 4, 5, "a", "b", "c", "d", "e"] </pre> 现在 `a`中存放了2个原始数组的内容, 看样子对内存优化做的不错。 另外,如果数组 `b`很大,`a`很小。 出于内存和速度的考虑,应该把较小的`a` 插入`b`中。 并且用`unshift()`方法代替 `push()` 即可, 对应的也要从大到小进行循环遍历: <pre>// 将数组 a 插入 b for (var i= a.length; i >= 0; i--) { b.unshift( a[i] ); } b; //["a", "b", "c", "d", "e",1, 2, 3, 4, 5] a = null </pre> ## Array.reduce 上面的for循环 很土,而且难以维护。当然有高大上的 <pre>//将 b 插入 a a = b.reduce(function(coll, item) { coll.push(item) return coll },a) a //[1, 2, 3, 4, 5, "a", "b", "c", "d", "e"] </pre> <pre> a = b.reduceRight(function(coll, item) { coll.push(item) return coll },a) a // [1, 2, 3, 4, 5, "e", "d", "c", "b", "a"] </pre> (注意回调函数后面别漏了数组a, 意思是:以数组a为叠加的初始值) `Arrar.reduce` 和`Array.reduceRight` 高大上得来又有点笨重, 而且一般人记不住,下面还有更高大上的方法 ## apply 和 es6展开运算符 <pre>//b 插入a a.unshift.apply(a, b) console.log(a) //["a", "b", "c", "d", "e", 1, 2, 3, 4, 5] a.push.apply(a,b) a // [1, 2, 3, 4, 5, "a", "b", "c", "d", "e"] a.push(...b) a //[1, 2, 3, 4, 5, "a", "b", "c", "d", "e"] </pre> 是不是big更高了。但是,事实上这种方法还是太乐观了. 在这两种情况下,不管是将 a 或 b 传递给 apply() 作为第二个参数(apply方式调用Function时第一个参数在内部变成this,即context,上下文,作用域), 还是使用 ... 展开运算符的方式, 实际上数组都会被打散成为函数的 arguments . 第一个主要的问题是,占用了双倍的内存(当然,是临时的!),因为需要将数组复制到函数栈之中. 此外,不同的JS引擎有不同的实现算法,可能会限制了函数可以传递的参数数量. 如果数组添加了一百万个元素, 那一定会超过函数栈所允许的大小, 不管是push() 或 unshift()调用. 这种方式只在几千个元素时可用,所以必须限制其不能超过一定范围. ## 总结 有很多变通的手法,但他们都有不同的优缺点,需要根据实际情况来选择.