es6之扩展运算符 (...) 简称三个点
es6之扩展运算符 (…) 简称三个点
对象的扩展运算符
理解对象的扩展运算符其实没有那么难,只要记住一句话就可以轻松掌握它:smiley:
对象中的扩展运算符(…)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中
1 | let bar = { a: 1, b: 2 }; |
上面的代码就相当于
1 | let bar = { a: 1, b: 2 }; |
**Object.assign
方法用于对象的合并,将源对象(source
)的所有可枚举属性,复制到目标对象(target
**)。
Object.assign
方法的第一个参数是目标对象,后面的参数都是源对象。(如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性)。 Object.assign
的详细使用请看这里
同样,如果用户自定义的属性,放在扩展运算符后面,则扩展运算符内部的同名属性会被覆盖掉。
1 | let bar = {a: 1, b: 2}; |
这里有点需要注意的是扩展运算符对对象实例的拷贝属于一种浅拷贝。肯定有人要问什么是浅拷贝?我们知道javascript
中有两种数据类型,分别是基础数据类型和引用数据类型。基础数据类型是按值访问的,常见的基础数据类型有Number
、Boolean
、String
、Null
、Undefined
、Symbol
、BigInt
,这类变量的拷贝的时候会完整的复制一份;引用数据类型比如Array
,在拷贝的时候拷贝的是对象的引用,当原对象发生变化的时候,拷贝对象也跟着变化,比如:
1 | let obj1 = { a: 1, b: 2}; |
上面这个例子扩展运算符拷贝的对象是基础数据类型,因此对obj2
的修改并不会影响obj1
1 | let obj1 = { a: 1, b: 2, c: {name: 'a'}}; |
这里可以看到,对obj2
的修改影响到了被拷贝对象obj1
,原因上面已经说了,因为obj1
中的对象c
是一个引用数据类型,拷贝的时候拷贝的是对象的引用。
解构赋值与扩展运算符
对象的解构赋值用于从一个对象取值,相当于将目标对象自身的所有可遍历的(enumerable)、但尚未被读取的属性,分配到指定的对象上面。所有的键和它们的值,都会拷贝到新对象上面。
1 | let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; |
注意:由于解构赋值要求等号右边是一个对象,所以如果等号右边是undefined
或null
,就会报错,因为它们无法转为对象。而且解构赋值必须是最后一个参数,否则会报错。
1 | let { ...z } = null; // 运行时错误 |
注意,扩展运算符的解构赋值,不能复制继承自原型对象的属性。
1 | let o1 = { a: 1 }; |
上面代码中,对象o3
复制了o2
,但是只复制了o2
自身的属性,没有复制它的原型对象o1
的属性。
如果扩展运算符后面是字符串,它会自动转成一个类似数组的对象,因此返回的不是空对象。
1 | {...'hello'} |
对象的扩展运算符等同于使用Object.assign()
方法.
1 | let aClone = { ...a }; |
上面的例子只是拷贝了对象实例的属性,如果想完整克隆一个对象,还拷贝对象原型的属性,可以采用下面的写法。
1 | // 写法一 |
比如看上面的例子 拷贝对象原型的属性:
1 | let o1 = { |
扩展运算符可以用于合并两个对象。
1 | let ab = { ...a, ...b }; |
数组中的扩展运算符
扩展运算符(spread
)是三个点(...
)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
1 | console.log(...[1, 2, 3]) |
它也可以替代函数的 apply
方法
1 | // ES5 的写法 |
比如举一个简单的例子:求一个数组中最大的元素
1 | // ES5 的写法 |
扩展运算符在数组中的常见应用
复制数组
数组是复合的数据类型,直接复制的话,只是复制了指向底层数据结构的指针,而不是克隆一个全新的数组。
1 | const a1 = [1, 2]; |
上面的例子中,`a2`并不是`a1`的克隆,而是指向同一份数据的另一个指针。对`a2`的修改会影响到`a1`。
但是 ES5 也有解决的方法 如下:
1 | const a1 = [1, 2]; |
上面代码中,a1
会返回原数组的克隆,再修改a2
就不会对a1
产生影响。
扩展运算符提供了复制数组的简便写法。如下: a2
都是a1
的克隆。
1 | const a1 = [1, 2]; |
还是记住那句话:扩展运算符(…)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中,这里参数对象是个数组,数组里面的所有对象都是基础数据类型,将所有基础数据类型重新拷贝到新的数组中。
- 可以将数组转换为参数序列
1 | function add(x, y) { |
与解构赋值结合
扩展运算符可以与解构赋值结合起来,用于生成数组
1
2
3
4
5
6
7const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
const [first, ...rest] = ["foo"];
first // "foo"
rest // []但是有一点要注意:**
如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。
**1
2
3
4const [...rest, last] = [1, 2, 3, 4, 5];
// 报错
const [first, ...rest, last] = [1, 2, 3, 4, 5];
// 报错扩展运算符还可以将字符串转为真正的数组。
1
2[...'hello']
// [ "h", "e", "l", "l", "o" ]
总结
对象中的扩展运算符(…)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中 。 好好回味一下这句话吧。
愿你的坚持终有收获。
Use this card to join the candyhome and participate in a pleasant discussion together .
Welcome to aqing's candyhome,wish you a nice day .