扩展运算符(…)–>数组
1、含义:将一个数组装转为用逗号分隔的参数序列,若扩展运算符后面跟的是一个空数组,则不产生任何效果
console.log(1,...[2,4,6]) // 1,2,4,6
console.log([...document.querySelectAll('div')]) // [<div>,<div>,<div>]
console.log(...[],1) //1
2、用途:
1、主要用于函数调用
function push(array,...items){
array.push(...items)
}
console.log(push([1,2],...[3,4,5])) // [1,2,3,4,5]
function add(x,y){
return x+y
}
console(add(...[1,2])) // 3
2、替代函数的apply方法,由于扩展运算符可以展开数组,所以不需要通过apply方法将数组转换为函数的参数
function f(x,y,z){
//...
}
var arr = [1,2,3]
//es5
f.apply(null,arr)
//es6
f(...arr)
// 通过push函数,将一个数组添加到另一个数组的尾部
// ES5的 写法
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
Array.prototype.push.apply(arr1, arr2);
// ES6 的写法
let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1.push(...arr2);
3、运用
1、复制数组
const arr1 = [1,2,3]
const arr2 = arr1;
//这个情况arr2并不是arr1的克隆,而是指向同一份数据的另一个指针,arr2变化会导致arr1的变化
//解决这种问题的方法:
// es5克隆
const arr3 = arr1.concat()
//es6
const arr4 = [...arr1]
const [...arr5] = a1
2、合并数组
const a1 = [1, 2,3];
const a2 = [4,5,6];
const a3 = [7];
//es5合并
a1.concat(a2,a3)
//es6
[...a1,...a2,...a3]
3、与解构赋值结合,用于生成数组,如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错
const [first,...rest] = [1,2,3,4] // first:1,rest:[2,3,4]
const [first,...rest] = [] // first:undefinde,rest:[]
//
const [first,...rest,last] = [1,2,3,4] //报错
4:字符串,扩展运算符可以将字符串装换为数组
let [...'hello'] // [ "h", "e", "l", "l", "o" ]
5、实现iterator接口对象,任何iterator对象都可以通过扩展运算符转为真正的数组
var nodeList = document.querySelectorAll('div');
var nodeList = document.querySelectorAll('div');
//querySelectorAll方法返回的是一个nodeList对象。它不是数组,而是一个类似数组的对象。
//这时,扩展运算符可以将其转为真正的数组,原因就在于NodeList对象实现了 Iterator 接口
扩展运算符(…)–> 对象
1:对象的扩展运算符(…)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。
let z = {a:3,b:4}
let n = {...z} // n: {a:3,b:4}
//等同于Object.assign方法
let n1 = Object.assign({},z)//这种方法只拷贝了对象实例的属性,如果需要克隆一个完整的对象,还需拷贝对象的原型属性,写法如下:
// 写法一
const clone1 ={
__proto__: Object.getPrototypeOf(obj),
...obj
}
//写法二
const2 = Object.assign(
Object.create(Object..getPrototypeOf(obj)),
obj
)
//写法三
const clone3 = Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
)
//备注:上面代码中,写法一的__proto__属性在非浏览器的环境不一定部署,因此推荐使用写法二和写法三
2、扩展运算符可以用来合并两个对象
let ab = {...a,...b}
//等同于
let ab = Object.assign({},a,b)
//如果用户自定义的属性,放在扩展运算符后面,则扩展运算符内部的同名属性会被覆盖掉。
let aWithOverrides = { ...a, x: 1, y: 2 };
// 等同于
let aWithOverrides = { ...a, ...{ x: 1, y: 2 } };
// 等同于
let x = 1, y = 2, aWithOverrides = { ...a, x, y };
// 等同于
let aWithOverrides = Object.assign({}, a, { x: 1, y: 2 });