一直对扩展运算符的使用云里雾里,趁着空闲,是时候拨开云雾见光明了~
数组的扩展运算符
应用
- 复制数组,注:数组元素类型为简单数据类型的,进行深拷贝;为复杂数据类型的(数组、对象、函数),进行浅拷贝
let arr1 = [1, 2];
let arr2 = [...arr1];
arr1[0] = 3;
console.log(arr1); // 3 2
console.log(arr2); // 1 2
let arr3 = [[1], 2];
let arr4 = [...arr3];
arr3[0][0] = 3;
console.log(arr3); // [3] 2
console.log(arr4); // [3] 2
- 合并数组:简单数据类型深拷贝,复杂数据类型浅拷贝
- 与解构赋值结合,用于数组的赋值只能放在参数的最后一位
实现原理及注意事项
-
扩展运算符内部调用的是数据结构的Iterator接口(Symbol.iterator),只要有这个接口的,就可以使用扩展运算符;
-
没有Iterator接口的,但是具有length属性,就可以使用Array.from转换为数组;
-
只要是部署了Iterator接口的数据结构,Array.from都能将其转为数组,也能使用扩展运算符。
-
注意:只有函数调用时,扩展运算符才可以放在圆括号中,否则会报错。
...[1, 2] // Uncaught SyntaxError: Unexpected token ... (...[1, 2]) // Uncaught SyntaxError: Unexpected token ... console.log(...[1, 2]) // 1 2
对象的扩展运算符
-
解构赋值,必须是最后一个参数,否则会报错;这种拷贝方式也是遵循简单数据类型深拷贝,复杂数据类型浅拷贝规则;扩展运算符的解构赋值,不能复制继承自原型对象的属性,如果仅仅是解构赋值,则没有这个规则。
const obj = Object.create({x: 1, y: 2}); obj.z = 3; let {x, ...newObj} = obj; console.log(x); // 1,x是直接解构赋值来的,所以有值 console.log(newObj.z) // 3 console.log(newObj.y) // undefined,newObj是扩展运算符的解构赋值来的,所以只有obj实例上的属性z,而没有其原型链上的属性y
-
作为对象的扩展运算符,
- 用于取出当前参数对象(obj)所有可遍历属性,拷贝到当前对象(obj2)之中;如果扩展运算符后边不是对象,会先将其转换为对象。
let obj = {x:1, y:2} let obj2 = {...obj, z:3} // {x:1, y:2, z:3} {...['a', 'b', 'c']} // {0: 'a', 1: b, 2: c},因为数组可以看成是特殊的对象 {...1} // {},过程是先将1转换成数值的包装对象Number{1},由于该对象没有自身属性,所以返回空对象 {...true} // {},同上
- 相当于使用Object.assign()方法,扩展运算符后边的属性,会覆盖扩展运算符里边同名的属性
let a = {x:1, y:2}; let obj1 = {...a}; // 等同于obj1 = Object.assign({}, a) let b = {z: 3}; let obj2 = {...a, ...b}; // 等同于obj2 = Object.assign({}, a, b); let obj3 = {...a, x: 4} // 扩展运算符在前边, 可定制某属性,等同于Object.assign({}, a, {x: 4}) let obj4 = {x: 0, ...a} // 扩展运算符在后边,可设置默认值,Object.assign({}, {x: 0}, a)
参考:《ECMAScript入门》阮一峰
网友评论