Ribbit's works

スプレッド構文とconcat、どちらを使うべきか【javascript】

#javascript
にメンテナンス済み
記事のトップ画像

結論

もともとスプレッド構文自体が、以前よりも強力で柔軟な配列リテラルを構築するために用意されたようで、使用できる環境であれば、スプレッド構文の方が良いようです。

mozilla の MDN Web Docs でも、

スプレッド構文を使用しない場合、既存の配列を一部として使用して新しい配列を作成するには、配列リテラル構文は十分ではなく、push(), splice(), concat() などを組み合わせて使う高圧的なコードを使用しなければなりません。 スプレッド構文 - Javascript | MDN

とあるので、可読性の面ではスプレッド構文が優位なようです。

速度については検証しましたが、ブラウザによって結果が大きく異なってしまいました。

速度

検証 1: 単純な合成

操作デモ

ご自身の環境でお試しできます。

concat, spread ボタンをクリックすると、それぞれの記法で 10 万回 × 10 回分の経過時間が表示されます。

See the Pen concat_spread by Local-Bias (@local-bias) on CodePen.

私の端末での検証結果

1000 万 × 10 回の 1 億回で検証。一応.length を付けました。

for (let i = 0; i < 10; i++) {
  const arr1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  const arr2 = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20];

  const start = new Date();
  for (let j = 0; j < 10000000; j++) {
    arr1.concat(arr2).length;
  }
  const end = new Date();

  console.log(`concat: ${i + 1}回目 > `, `${end.getTime() - start.getTime()}ms`);
}

for (let i = 0; i < 10; i++) {
  const arr1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  const arr2 = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20];

  const start = new Date();
  for (let j = 0; j < 10000000; j++) {
    [...arr1, ...arr2].length;
  }
  const end = new Date();

  console.log(`スプレッド構文: ${i + 1}回目 > `, `${end.getTime() - start.getTime()}ms`);
}

結果

// Google Chrome
concat: 1回目 > 1695ms
concat: 2回目 > 1708ms
concat: 3回目 > 1667ms
concat: 4回目 > 1771ms
concat: 5回目 > 1606ms
concat: 6回目 > 1611ms
concat: 7回目 > 1601ms
concat: 8回目 > 1603ms
concat: 9回目 > 1751ms
concat: 10回目 > 1611ms
スプレッド構文: 1回目 > 550ms
スプレッド構文: 2回目 > 542ms
スプレッド構文: 3回目 > 528ms
スプレッド構文: 4回目 > 540ms
スプレッド構文: 5回目 > 519ms
スプレッド構文: 6回目 > 521ms
スプレッド構文: 7回目 > 553ms
スプレッド構文: 8回目 > 588ms
スプレッド構文: 9回目 > 581ms
スプレッド構文: 10回目 > 611ms

// Firefox
concat: 1回目 > 3160ms
concat: 2回目 > 3197ms
concat: 3回目 > 3205ms
concat: 4回目 > 4421ms
concat: 5回目 > 3921ms
concat: 6回目 > 3377ms
concat: 7回目 > 3527ms
concat: 8回目 > 3603ms
concat: 9回目 > 3198ms
concat: 10回目 > 3580ms
スプレッド構文: 1回目 > 11586ms
スプレッド構文: 2回目 > 12036ms
スプレッド構文: 3回目 > 12065ms
スプレッド構文: 4回目 > 9119ms
スプレッド構文: 5回目 > 9235ms
スプレッド構文: 6回目 > 10430ms
スプレッド構文: 7回目 > 9367ms
スプレッド構文: 8回目 > 9136ms
スプレッド構文: 9回目 > 9091ms
スプレッド構文: 10回目 > 9577ms

Chrome だとスプレッド構文が 3 倍速く、Firefox だとスプレッド構文が 3 倍遅いです。

検証 2: 結合を繰り返す

今度は配列の結合を繰り返し、どんどん要素数が増えていく場合です。

1 億回は私のパソコンでは耐えられないので、10000 回 × 10 回です。

for (let i = 0; i < 10; i++) {
  const arr1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  const arr2 = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
  let con = [];

  const start = new Date();
  for (let j = 0; j < 10000; j++) {
    con = con.concat(arr1, arr2);
  }
  const end = new Date();

  console.log(`concat: ${i + 1}回目 > `, `${end.getTime() - start.getTime()}ms`);
}

for (let i = 0; i < 10; i++) {
  const arr1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  const arr2 = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
  let con = [];

  const start = new Date();
  for (let j = 0; j < 10000; j++) {
    con = [...con, ...arr1, ...arr2];
  }
  const end = new Date();

  console.log(`スプレッド構文: ${i + 1}回目 > `, `${end.getTime() - start.getTime()}ms`);
}

結果

// Google Chrome
concat: 1回目 > 5477ms
concat: 2回目 > 4882ms
concat: 3回目 > 5439ms
concat: 4回目 > 5256ms
concat: 5回目 > 5015ms
concat: 6回目 > 5087ms
concat: 7回目 > 5029ms
concat: 8回目 > 5235ms
concat: 9回目 > 5128ms
concat: 10回目 > 5183ms
スプレッド構文: 1回目 > 6518ms
スプレッド構文: 2回目 > 6368ms
スプレッド構文: 3回目 > 6823ms
スプレッド構文: 4回目 > 6541ms
スプレッド構文: 5回目 > 6624ms
スプレッド構文: 6回目 > 7964ms
スプレッド構文: 7回目 > 6860ms
スプレッド構文: 8回目 > 7262ms
スプレッド構文: 9回目 > 7183ms
スプレッド構文: 10回目 > 6805ms

// Mozilla Firefox
concat: 1回目 >  29435ms
concat: 2回目 >  32958ms
concat: 3回目 >  36732ms
concat: 4回目 >  34883ms
concat: 5回目 >  33363ms
concat: 6回目 >  31847ms
concat: 7回目 >  33514ms
concat: 8回目 >  34851ms
concat: 9回目 >  34995ms
concat: 10回目 >  29991ms
スプレッド構文: 1回目 >  66842ms
スプレッド構文: 2回目 >  54571ms
スプレッド構文: 3回目 >  49920ms
スプレッド構文: 4回目 >  54506ms
スプレッド構文: 5回目 >  62879ms
スプレッド構文: 6回目 >  49636ms
スプレッド構文: 7回目 >  50667ms
スプレッド構文: 8回目 >  48355ms
スプレッド構文: 9回目 >  51219ms
スプレッド構文: 10回目 >  50550ms