web-dev-qa-db-fra.com

propagation opérateur vs array.concat ()

Quelle est la différence entre spread operator Et array.concat()

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

Fonction Array.concat ()

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

Les deux résultats sont les mêmes. Alors, quel genre de scénarios nous voulons utiliser? Et quel est le meilleur pour la performance?

23
Ramesh Rajendran

Bien console.log(['one', 'two', 'three', 'four', 'five']) a le même résultat, alors pourquoi utiliser soit ici? : P

En général, vous utiliseriez concat lorsque vous avez deux (ou plusieurs) tableaux de sources arbitraires, et vous utiliseriez la syntaxe de propagation dans le littéral de tableau si les éléments supplémentaires qui font toujours partie du tableau sont connus auparavant. Donc, si vous aviez un littéral de tableau avec concat dans votre code, utilisez simplement la syntaxe spread et utilisez simplement concat sinon:

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

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

De plus, les deux alternatives se comportent différemment lorsqu'il s'agit de valeurs autres que des tableaux.

29
Bergi

Comme @Bergi l'a dit, concat et les spreads sont très différents lorsque l'argument n'est pas un tableau.

Lorsque l’argument n’est pas un tableau, concat "le rend" (c’est-à-dire qu'il convertit x en [x]) et continue avec ce tableau temporaire, tandis que ... tente de l'itérer et échoue s'il ne le peut pas. Considérer:

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' ]

Ici, concat traite la chaîne de manière atomique, tandis que ... utilise son itérateur par défaut, caractère par caractère.

Un autre exemple:

x = 99;

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

Encore une fois, pour concat le nombre est un atome, ... tente de le parcourir et échoue.

Finalement:

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 n'effectue aucune tentative pour itérer le générateur et l'ajoute dans son ensemble, tandis que ... récupère joliment toutes les valeurs.

Pour résumer, lorsque vos arguments sont éventuellement non-tableaux, le choix entre concat et ... dépend de si vous voulez qu’ils soient itérés.

En termes de performances, concat est plus rapide, probablement parce qu'il peut tirer parti d'optimisations spécifiques aux tableaux, tandis que ... doit être conforme au protocole d’itération commun. Horaires:

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

La seule différence que je pense être valable est que l'utilisation de l'opérateur spread pour une taille de tableau importante génère une erreur de Maximum call stack size exceeded, Ce que vous pouvez éviter en utilisant l'opérateur 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

Je réponds simplement à la question de performance car il existe déjà de bonnes réponses concernant les scénarios. J'ai écrit un test et l'ai exécuté sur les navigateurs les plus récents. Ci-dessous les résultats et le code.

/*
 * 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
 * --------------------------------------------------
*/

Ci-dessous le code que j'ai écrit et utilisé.

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);

J'ai également écrit sur le sujet dans mon blog: https://www.malgol.com/how-to-merge-two-arrays-in-javascript/ .

1