spread operator vs array.concat()

Ram*_*ran 28 javascript arrays operators typescript angular

spread operator和之间有什么区别array.concat()

let parts = ['four', 'five'];
let numbers = ['one', 'two', 'three'];
console.log([...numbers, ...parts]);
Run Code Online (Sandbox Code Playgroud)

Array.concat()函数

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

两个结果都是一样的.那么,我们想要使用它们的场景是什么?哪一个最适合表现?

geo*_*org 39

正如@Bergi所说,concat当参数不是数组时,差异非常不同.

当参数不是数组时,将其concat" 数组化"(即转换...concat)并继续执行此临时数组,同时...尝试迭代它,如果不能则会失败.考虑:

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' ]
Run Code Online (Sandbox Code Playgroud)

这里,concat以原子方式处理字符串,同时...使用其默认迭代器char-by-char.

另一个例子:

x = 99;

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

同样,因为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' ]
Run Code Online (Sandbox Code Playgroud)

concat不会尝试迭代生成器并将其作为一个整体附加,同时...很好地从中获取所有值.

总而言之,当你的参数可能是非数组时,在concat和之间的选择Symbol.isConcatSpreadable取决于你是否希望它们被迭代.

性能方面true要快得多,可能是因为它可以从特定于阵列的优化中受益,同时false必须符合常见的迭代协议.时序:

str = 'hello'
console.log([1,2,3].concat(str)) // [1,2,3, 'hello']

str = new String('hello');
str[Symbol.isConcatSpreadable] = true;
console.log([1,2,3].concat(str)) // [ 1, 2, 3, 'h', 'e', 'l', 'l', 'o' ]
Run Code Online (Sandbox Code Playgroud)

在最新的Chrome中,true速度提高了约5倍.

  • 这应该是正确的答案。比伯吉的答案更不主观。 (15认同)

Ber*_*rgi 33

那么console.log(['one', 'two', 'three', 'four', 'five'])结果也一样,为什么要在这里使用?:P

通常,concat当您有来自任意源的两个(或更多)数组时,您将使用,如果之前已知的是始终是数组的一部分的其他元素,则可以在数组文字中使用spread语法.因此,如果你concat的代码中有一个数组文字 ,那么只需使用扩展语法,然后使用concat其他方法:

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

[x, y].concat(a) // bad :-(
[x, y, ...a]    // good :-)
Run Code Online (Sandbox Code Playgroud)

在处理非数组值时,这两种选择的行为也完全不同.

  • FWIW,性能之间存在可衡量的差异。参见https://jsperf.com/spread-vs-concat-vs-push (3认同)
  • @DrazenBjelovuk `.concat(x)` 让读者假设 `x` 也是一个数组。当然,“concat”也可以处理非数组值,但在我看来,这不是它的主要操作模式。特别是如果“x”是任意(未知)值,则需要编写“.concat([x])”以确保它始终按预期工作。一旦你必须编写数组文字,我说你应该只使用扩展语法而不是“concat”。 (2认同)

Mir*_*nas 9

更新

Concat 现在总是比spread. 以下基准测试显示了小型和大型数组的连接:https://jsbench.me/nyla6xchf4/1

在此输入图像描述

// preparation
const a = Array.from({length: 1000}).map((_, i)=>`${i}`);
const b = Array.from({length: 2000}).map((_, i)=>`${i}`);
const aSmall = ['a', 'b', 'c', 'd'];
const bSmall = ['e', 'f', 'g', 'h', 'i'];

const c = [...a, ...b];
// vs
const c = a.concat(b);

const c = [...aSmall, ...bSmall];
// vs
const c = aSmall.concat(bSmall)
Run Code Online (Sandbox Code Playgroud)

以前的:

尽管在大数组上的性能方面,一些答复是正确的,但在处理小数组时,性能却有很大不同。

您可以在https://jsperf.com/spread-vs-concat-size-agnostic自行检查结果

正如您所看到的,较小阵列的传播速度快了 50%,而concat大型阵列的传播速度则快了数倍。

  • 链接已损坏 - 因此,最好始终提供链接内容的摘要,以防链接损坏。 (5认同)

Pau*_*ell 7

concat和之间有一个非常重要的区别push,前者不会改变底层数组,要求您将结果分配给相同或不同的数组:

let things = ['a', 'b', 'c'];
let moreThings = ['d', 'e'];
things.concat(moreThings);
console.log(things); // [ 'a', 'b', 'c' ]
things.push(...moreThings);
console.log(things); // [ 'a', 'b', 'c', 'd', 'e' ]
Run Code Online (Sandbox Code Playgroud)

我见过由concat更改数组的假设引起的错误(为朋友谈论;)。


Ank*_*wal 6

我认为有效的一个区别是,对较大的数组大小使用扩展运算符会给您带来错误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)
Run Code Online (Sandbox Code Playgroud)

  • 您应该澄清当函数调用在内部使用传播时会使用堆栈。然而,当它只是一个数组文字并且使用了扩展时,不会使用任何堆栈,因此不会发生最大调用堆栈。 (4认同)
  • 这种传播语法(函数调用)的使用不是被问到的(数组文字)。 (2认同)
  • 这与问题无关并且具有误导性 (2认同)

Vas*_*şte 5

我只回答性能问题,因为有关方案已经有了很好的答案。我编写了一个测试,并在最新的浏览器上执行了该测试。下面的结果和代码。

/*
 * 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
 * --------------------------------------------------
*/
Run Code Online (Sandbox Code Playgroud)

下面是我编写和使用的代码。

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);
Run Code Online (Sandbox Code Playgroud)

我还在博客中写了关于该主题的文章:https : //www.malgol.com/how-to-merge-two-arrays-in-javascript/

  • 谢谢,就真正重要的事情而言,这实际上是一个有用的答案。 (9认同)
  • 我很少有 10.000.000 个元素。宁愿/也希望看到合并 10、100 或 1000 个元素以及多次合并的比较。 (3认同)