Javascript 展开运算符 vs array.concat()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/48865710/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
spread operator vs array.concat()
提问by Ramesh Rajendran
What is the difference between spread operatorand array.concat()
是有什么区别spread operator和array.concat()
let parts = ['four', 'five'];
let numbers = ['one', 'two', 'three'];
console.log([...numbers, ...parts]);
Array.concat() function
Array.concat() 函数
let parts = ['four', 'five'];
let numbers = ['one', 'two', 'three'];
console.log(numbers.concat(parts));
Both results are same. So, what kind of scenarios we want to use them? And which one is best for performance?
两个结果是一样的。那么,我们想在什么样的场景中使用它们呢?哪一种最适合性能?
回答by georg
concatand spreads are very different when the argument is not an array.
concat当参数不是数组时,点差非常不同。
When the argument is not an array, concatadds it as a whole, while ...tries to iterate it and fails if it can't. Consider:
当参数不是数组时,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' ]
Here, concattreats the string atomically, while ...uses its default iterator, char-by-char.
在这里,concat原子地处理字符串,同时...使用其默认迭代器 char-by-char。
Another example:
另一个例子:
x = 99;
console.log(a.concat(x)); // [1, 2, 3, 99]
console.log([...a, ...x]); // TypeError: x is not iterable
Again, for concatthe number is an atom, ...tries to iterate it and fails.
同样,因为concat数字是一个原子,...尝试迭代它并失败。
Finally:
最后:
function* gen() { yield *'abc' }
console.log(a.concat(gen())); // [ 1, 2, 3, Object [Generator] {} ]
console.log([...a, ...gen()]); // [ 1, 2, 3, 'a', 'b', 'c' ]
concatmakes no attempt to iterate the generator and appends it as a whole, while ...nicely fetches all values from it.
concat不尝试迭代生成器并将其作为一个整体附加,同时...很好地从中获取所有值。
To sum it up, when your arguments are possibly non-arrays, the choice between concatand ...depends on whether you want them to be iterated.
总而言之,当您的参数可能是非数组时,在concat和之间的选择...取决于您是否希望它们被迭代。
The above describes the default behaviour of concat, however, ES6 provides a wayto override it with Symbol.isConcatSpreadable. By default, this symbol is truefor arrays, and falsefor everything else. Setting it to truetells concatto iterate the argument, just like ...does:
上面描述了 的默认行为concat,但是,ES6提供了一种使用Symbol.isConcatSpreadable. 默认情况下,此符号true用于数组以及false其他所有内容。将其设置为true告诉concat迭代参数,就像这样...做:
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' ]
Performance-wise concatis faster, probably because it can benefit from array-specific optimizations, while ...has to conform to the common iteration protocol. Timings:
性能方面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');
回答by Bergi
Well console.log(['one', 'two', 'three', 'four', 'five'])has the same result as well, so why use either here? :P
Wellconsole.log(['one', 'two', 'three', 'four', 'five'])也有相同的结果,那么为什么在这里使用任何一个呢?:P
In general you would use concatwhen you have two (or more) arrays from arbitrary sources, and you would use the spread syntax in the array literal if the additional elements that are always part of the array are known before. So if you would have an array literal with concatin your code, just go for spread syntax, and just use concatotherwise:
通常,concat当您有来自任意来源的两个(或更多)数组时,您会使用扩展语法,如果之前知道始终是数组一部分的附加元素,则您将在数组文字中使用扩展语法。因此,如果您concat的代码中有一个数组文字 ,只需使用扩展语法,concat否则使用:
[...a, ...b] // bad :-(
a.concat(b) // good :-)
[x, y].concat(a) // bad :-(
[x, y, ...a] // good :-)
Also the two alternatives behave quite differently when dealing with non-array values.
在处理非数组值时,这两种替代方法的行为也大不相同。
回答by Vasile Alexandru Pe?te
I am replying just to the performance question since there are already good answers regarding the scenarios. I wrote a test and executed it on the most recent browsers. Below the results and the 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
* --------------------------------------------------
*/
Below the code I wrote and used.
在我编写和使用的代码下方。
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);
I also wrote about the topic in my blog: https://www.malgol.com/how-to-merge-two-arrays-in-javascript/.
我还在我的博客中写过这个话题:https: //www.malgol.com/how-to-merge-two-arrays-in-javascript/。
回答by Ankit Agarwal
The one difference I think is valid is that using spread operator for large array size will give you error of Maximum call stack size exceededwhich you can avoid using the concatoperator.
我认为有效的一个区别是,对大数组大小使用扩展运算符会给您带来错误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)

