web-dev-qa-db-ja.com

スプレッド演算子vs array.concat()

spread operatorarray.concat()の違いは何ですか

let parts = ['four', 'five'];
let numbers = ['one', 'two', 'three'];
console.log([...numbers, ...parts]);

Array.concat()関数

let parts = ['four', 'five'];
let numbers = ['one', 'two', 'three'];
console.log(numbers.concat(parts));

両方の結果は同じです。それでは、どのようなシナリオを使用したいのでしょうか?そして、パフォーマンスに最適なのはどれですか?

23

console.log(['one', 'two', 'three', 'four', 'five'])も同じ結果になるので、ここでどちらを使用するのですか? :P

一般に、任意のソースから2つ(またはそれ以上)の配列がある場合はconcatを使用し、常に配列の一部である追加要素が以前にわかっている場合は、配列リテラルでspread構文を使用します。したがって、コードにconcatを含む配列リテラルがある場合は、スプレッド構文に進み、そうでない場合はconcatを使用します。

[...a, ...b] // bad :-(
a.concat(b) // good :-)

[x, y].concat(a) // bad :-(
[x, y, ...a]    // good :-)

また、配列以外の値を処理する場合、2つの選択肢の動作はまったく異なります。

29
Bergi

@Bergiが言ったように、引数が配列でない場合、concatとスプレッドは非常に異なります。

引数が配列でない場合、concatはそれを「配列」(つまり、x[x]に変換)し、この一時配列を続行しますが、...は反復を試み、失敗した場合は失敗します。考慮してください:

a = [1, 2, 3]
x = 'hello';

console.log(a.concat(x));  // [ 1, 2, 3, 'hello' ]
console.log([...a, ...x]); // [ 1, 2, 3, 'h', 'e', 'l', 'l', 'o' ]

ここで、concatは文字列をアトミックに処理しますが、...はデフォルトのイテレータchar-by-charを使用します。

もう一つの例:

x = 99;

console.log(a.concat(x));   // [1, 2, 3, 99]
console.log([...a, ...x]);  // TypeError: x is not iterable

繰り返しますが、concatの場合、数値はアトムであり、...はそれを反復しようとして失敗します。

最後に:

function* gen() { yield *'abc' }

console.log(a.concat(gen()));   // [ 1, 2, 3, Object [Generator] {} ]
console.log([...a, ...gen()]);  // [ 1, 2, 3, 'a', 'b', 'c' ]

concatはジェネレーターを反復しようとせず、全体として追加しますが、...はすべての値を適切にフェッチします。

要約すると、引数が配列でない可能性がある場合、concat...の選択は、それらを反復させるかどうかによって異なります。

パフォーマンス面では、concatはより高速です。おそらく、...は共通の反復プロトコルに準拠する必要がありますが、おそらくアレイ固有の最適化の恩恵を受けることができるからです。タイミング:

let big = (new Array(1e5)).fill(99);
let i, x;

console.time('concat-big');
for(i = 0; i < 1e2; i++) x = [].concat(big)
console.timeEnd('concat-big');

console.time('spread-big');
for(i = 0; i < 1e2; i++) x = [...big]
console.timeEnd('spread-big');


let a = (new Array(1e3)).fill(99);
let b = (new Array(1e3)).fill(99);
let c = (new Array(1e3)).fill(99);
let d = (new Array(1e3)).fill(99);

console.time('concat-many');
for(i = 0; i < 1e2; i++) x = [1,2,3].concat(a, b, c, d)
console.timeEnd('concat-many');

console.time('spread-many');
for(i = 0; i < 1e2; i++) x = [1,2,3, ...a, ...b, ...c, ...d]
console.timeEnd('spread-many');
32
georg

私が有効だと思う1つの違いは、大きな配列サイズにスプレッド演算子を使用すると、Maximum call stack size exceededのエラーが発生し、concat演算子の使用を回避できることです。

var  someArray = new Array(600000);
var newArray = [];
var tempArray = [];


someArray.fill("foo");

try {
  newArray.Push(...someArray);
} catch (e) {
  console.log("Using spread operator:", e.message)
}

tempArray = newArray.concat(someArray);
console.log("Using concat function:", tempArray.length)
5
Ankit Agarwal

シナリオに関する良い回答が既にあるので、パフォーマンスの質問に答えています。テストを作成し、最新のブラウザーで実行しました。結果とコードの下。

/*
 * Performance results.
 * Browser           Spread syntax      concat method
 * --------------------------------------------------
 * Chrome 75         626.43ms           235.13ms
 * Firefox 68        928.40ms           821.30ms
 * Safari 12         165.44ms           152.04ms
 * Edge 18           1784.72ms          703.41ms
 * Opera 62          590.10ms           213.45ms
 * --------------------------------------------------
*/

私が書いて使用したコードの下。

const array1 = [];
const array2 = [];
const mergeCount = 50;
let spreadTime = 0;
let concatTime = 0;

// Used to popolate the arrays to merge with 10.000.000 elements.
for (let i = 0; i < 10000000; ++i) {
    array1.Push(i);
    array2.Push(i);
}

// The spread syntax performance test.
for (let i = 0; i < mergeCount; ++i) {
    const startTime = performance.now();
    const array3 = [ ...array1, ...array2 ];

    spreadTime += performance.now() - startTime;
}

// The concat performance test.
for (let i = 0; i < mergeCount; ++i) {
    const startTime = performance.now();
    const array3 = array1.concat(array2);

    concatTime += performance.now() - startTime;
}

console.log(spreadTime / mergeCount);
console.log(concatTime / mergeCount);

また、ブログでこのトピックについて書いた: https://www.malgol.com/how-to-merge-two-arrays-in-javascript/