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' ]
在这里,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
,然而,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' ]
性能方面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');