这个例子的输出是一样的,但它在幕后的行为并不相同,
考虑(检查浏览器的控制台):
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将保留数组中的空槽,而 Spread 将用undefined
值替换它们。
输入Symbol.iterator和Symbol.isConcatSpreadable:
的传播操作者使用@@iterator
通过数组和数组等状物体符号迭代:
- Array.prototype
- TypedArray.prototype
- 字符串原型
- 地图.prototype
- 集.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
行为有所不同,Objects
因为它们不可迭代
var obj = {'key1': 'value1'};
var array = [...obj]; // TypeError: obj is not iterable
var objCopy = {...obj}; // copy
它将自己的可枚举属性从提供的对象复制到新对象上。
展开运算符更快,请检查spread-into-array-vs-concat(至少从 Chrome 67 开始)
并检查三个点如何在某些用例中更改 javascript,其中包括解构赋值( Array 或 Object ):
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" ]