Javascript推送到数组 - 性能

时间:2016-08-13 23:26:13

标签: javascript arrays performance lodash

考虑我们有2个非常大的大小为N和M的数组,

var array1 = [1,2,3...N],
    array2 = [a,b,c...M];

将array2推送到array1的最优化方法是什么?

使用原生JavaScript,

Array.prototype.push.apply(array1,array2) 

使用Lodash,

array1 = _.concat(array1, array2)

由于lodash制作源数组的副本,我猜它的复杂性会因为与原生javascript相比增加O(N)。 推送阵列还有其他优化的方法吗? 另外,为什么像lodash这样极受欢迎的库不能提供修改现有阵列以提高性能的选项?

3 个答案:

答案 0 :(得分:1)

push.apply(array1, array2)是最优的,因为它修改了array1的引用,但没有复制/返回它以重新分配。

答案 1 :(得分:1)

让我们做一个简单的测试,看看。当数组通过apply作为参数传递给push时,大小就像150K(在我目前的情况下它发生在250076之后),你会注意到我在评论中提到的范围错误。这是一个主要问题,因为对于较小的阵列,性能差异无论如何都可以忽略不计。因此,如果要连接的数组足以让您关注操作的性能,则应避免使用push with apply或spread运算符。

function measureConcatPerformances() {
  var len = +arrayLength.value,
    ar1 = new Array(len).fill().map(e => ~~(Math.random() * 1000000)),
    ar2 = new Array(len).fill().map(e => ~~(Math.random() * 1000000)),
    ts = 0,
    te = 0;
  
  myError.textContent = "";
  ts = performance.now();
  for (var i = 0; i < len; i++) ar1[ar1.length] = ar2[i];
  te = performance.now();
  forLoopResult.textContent = "ar1 and ar2 concataned in: " + (te - ts) + "msec by for loop";

  ar1 = new Array(len).fill().map(e => ~~(Math.random() * 1000000));
  ar2 = new Array(len).fill().map(e => ~~(Math.random() * 1000000));

  ts = performance.now();
  for (var val of ar2) ar1[ar1.length] = val;
  te = performance.now();
  forOfResult.textContent = "ar1 and ar2 concataned in: " + (te - ts) + "msec by for of loop";

  ar1 = new Array(len).fill().map(e => ~~(Math.random() * 1000000));
  ar2 = new Array(len).fill().map(e => ~~(Math.random() * 1000000));
  try{
  ts = performance.now();
  Array.prototype.push.apply(ar1, ar2);
  te = performance.now();
  applyResult.textContent = "ar1 and ar2 concataned in: " + (te - ts) + "msec by apply";
  } catch(err) {myError.textContent = "Error at apply: " + err}
  
  ar1 = new Array(len).fill().map(e => ~~(Math.random() * 1000000));
  ar2 = new Array(len).fill().map(e => ~~(Math.random() * 1000000));

  ts = performance.now();
  ar1 = ar1.concat(ar2);
  te = performance.now();
  concatResult.textContent = "ar1 and ar2 concataned in: " + (te - ts) + "msec by concat";
}

myButton.addEventListener("click", measureConcatPerformances);
<input id="arrayLength" type="number" min="0" value = 0>
<button id="myButton">Length</button>
  <p id="forLoopResult"></p>
  <p id="forOfResult"></p>
  <p id="applyResult"></p>
  <p id="concatResult"></p>
  <p id="myError" style="color:red"></p>

答案 2 :(得分:0)

您可以使用rest element将数组元素收集到另一个数组中;在创建两个数组时将array2收集到array1

var array1 = [...[1,2,3] ...(array2 = ["a", "b", "c"])];