这个例子的输出是一样的,但在底层的行为是不一样的,
考虑(检查浏览器的控制台):
var x = [], y = [];
x[1] = "a";
y[1] = "b";
var usingSpread = [...x, ...y];
var usingConcat = x.concat(y);
console.log(usingSpread); // [ undefined, "a", undefined, "b"]
console.log(usingConcat); // [ , "a", , "b"]
console.log(1 in usingSpread); // true
console.log(1 in usingConcat); // false
Array.prototype.concat 将保留数组中的empty slots,而Spread 将用undefined 值替换它们。
输入Symbol.iterator和Symbol.isConcatSpreadable:
Spread 运算符使用@@iterator 符号来遍历数组和类似数组的对象,例如:
- Array.prototype
- TypedArray.prototype
- String.prototype
- Map.prototype
- Set.prototype
(这就是为什么你可以在他们身上使用for .. of)
我们可以覆盖默认的iterator 符号来查看spread 运算符的行为:
var myIterable = ["a", "b", "c"];
var myIterable2 = ["d", "e", "f"];
myIterable[Symbol.iterator] = function*() {
yield 1;
yield 2;
yield 3;
};
console.log(myIterable[0], myIterable[1], myIterable[2]); // a b c
console.log([...myIterable]); // [1,2,3]
var result = [...myIterable, ...myIterable2];
console.log(result); // [1,2,3,"d","e","f"]
var result2 = myIterable.concat(myIterable2);
console.log(result2); // ["a", "b", "c", "d", "e", "f"]
另一方面,@@isConcatSpreadable 是
一个布尔值属性,如果为 true,则表示对象应通过 Array.prototype.concat 展平为其数组元素。
如果设置为false,Array.concat 将不会展平数组:
const alpha = ['a', 'b', 'c'];
const numeric = [1, 2, 3];
let alphaNumeric = alpha.concat(numeric);
// console.log(alphaNumeric);
numeric[Symbol.isConcatSpreadable] = false;
alphaNumeric = alpha.concat(numeric);
// alphaNumeric = [...alpha, ...numeric];
// the above line will output : ["a","b","c",1,2,3]
console.log(JSON.stringify(alphaNumeric)); // ["a","b","c",[1,2,3]]
但是,spread behaves differently 与 Objects 一样,因为它们是 not iterable
var obj = {'key1': 'value1'};
var array = [...obj]; // TypeError: obj is not iterable
var objCopy = {...obj}; // copy
它将自己的可枚举属性从提供的对象复制到新对象。
扩展运算符更快,检查spread-into-array-vs-concat(至少从 Chrome 67 开始)
查看how three dots changed javascript 的一些用例,其中有Destructuring assignment(数组或对象):
const arr = [1, 2, 3, 4, 5, 6, 7];
const [first, , third, ...rest] = arr;
console.log({ first, third, rest });
并将字符串拆分为字符数组:
console.log( [...'hello'] ) // [ "h", "e" , "l" , "l", "o" ]