扩展运算符( spread )是三个点(...)。它好比 rest 参数的逆运算,rest是可以使用function (...arr){}的形式,将传进来东西全部接受进arr。而扩展运算符就是逆过程,将收集起来的东西再分散展开,将一个数组转为用逗号分隔的参数序列。
1.合并数组与对象
let a = [1, 2, 3];
let b = [4, 5, 6];
let c = [...a, ...b];
console.log(c) // [1,2,3,4,5,6]
const objA = {
a:1,
b:2
};
consto bjB = {
c:3,
d:4
}
console.log({
...objA,
...objB
}); //{a: 1, b: 2, c: 3, d: 4}
如果要在数组任意位置进行插入,可以用展开运算符
let arr1 = [1, 2, 3, 4];
const arr2 = ["1", "2", ...arr1, "3", "4"]
console.log(arr2); // ["1", "2", 1, 2, 3, 4, "3", "4"]
如果想要整合两个数组,并且想把某个数组放在另一个数组的任意特定位置上,要配合Math函数使用
展开运算符将数组“展开”成为不同的参数,所以任何可接收任意数量的参数的函数,都能够使用展开运算符来传参
let number = [9, 4, 7, 1];
console.log(Math.min(...number)); // 1
console.log(Math.min(number));//NAN
2.可以将数组转换为参数序列
function add(x, y) {
return x + y;
}
const numbers = [4, 38];
add(...numbers)
console.log(add(...numbers)) // 42
console.log(add(numbers)) //4,38undefined
还可以将数组转化为逗号分隔的参数序列
const person = ['nam1', 'nam2', 'nam3', 'nam4'];
function getName() {
console.log(arguments);
}
getName(person); // 当在调用数组时 没用扩展运算符时 得到的就是原来的函数:
getName(...person);
3.解构赋值
let a = [1, 2, 3, 4, 5, 6]
let [c, ...d] = a
console.log(c); // 1
console.log(d); // [2,3,4,5,6]]
如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。
const [...rest, last] = [1, 2, 3, 4, 5]; // 报错
const [first, ...rest, last] = [1, 2, 3, 4, 5]; // 报错
对象的解构赋值:明确指出的赋值名字要相对。比如const中的a和b要对应对象里面的键名,而展开运算符可以不用相对。
const {
a,
b,
...data
} = {
'a': 111,
'b': 222,
'c': 333,
'd': 444
}
console.log(a); // 111
console.log(b); // 222
console.log(data); // { c: 333, d: 444 }
对象中定义一个变量a,一个变量b,在被解构的对象中进行匹配,匹配到与变量名相同的key值,就把value赋值给该变量,匹配与顺序无关,剩下的键值对以对象形式赋值给展开运算符作用的变量。
const {
a: c,
b,
...data
} = {
'a': 111,
'b': 222,
'c': 333,
'd': 444
}
// console.log(a);
// 冒号前是用于匹配的变量名,冒号后是变量名的别名,匹配到的值最后会赋给别名,此时的a是没有值的,输出会报错。
console.log(b); // 222
console.log(c); // 111
console.log(data); // { c: 333, d: 444 }
4.数据构造
两个对象连接返回新的对象
let x = {
name: 'autumn'
}
let y = {
age: 18
}
let z = {
...x,
...y
}
console.log(z) //{name: 'autumn', age: 18}
两个数组连接返回新的数组
let x = ['autumn']
let y = ['wscats']
let z = [...x, ...y]
console.log(z) // ["autumn", "wscats"]
数组加上对象返回新的数组
let x = [{
name: 'autumn'
}]
let y = {
name: 'wscats'
}
let z = [...x, y];
console.log(z);
数组+字符串
let x = ['autumn'];
let y = 'wscats';
let z = [...x, y];
console.log(z); //['autumn', 'wscats']
数组+对象
let x = {
name: ['autumn', 'wscats'],
age: 18
}
let y = {
...x, //name: ['autumn','wscats'],age:18
arr: [...x.name] //['autumn','wscats']
}
console.log(y)
5.字符串转为数组,正确识别 32 位的 Unicode 字符
console.log([...'siva']) // ['s','i','v','a']
console.log([...'x\uD83D\uDE80y'].length) // 3
6.替代apply
扩展运算符与apply一样是展开数组,可将数组转为函数的参数
function add(x, y, z) {
console.log(x + y + z)
};
var arr = [6, 7, 8];
//ES5写法 :add.apply(null,arr); //21
//ES6写法 :
add(...arr); //21
7.浅拷贝
数组
var a = [1, 2, 4]
var b = [...a]
var c = a
a.push(6)
console.log(c) // [1,2,4]
对象
var a = {
a: 1
}
var b = {
...a
}
//等价于
// let baz = Object.assign({}, a); // { a: 1 }
// a.a = 5
console.log(b.a) // 1
如果只是一层数组或是对象,其元素只是简单类型的元素,那么属于深拷贝(就是一层拷贝,暂时就理解为深拷贝)
let aa = {
age: 18,
name: 'aaa'
}
let bb = {...aa};
bb.age = 22;
console.log(aa.age); // 18
如果数组或对象中的元素是引用类型的元素,那么就是浅拷贝
let aa = {
age: 18,
name: 'aaa',
address: {
city: 'shanghai'
}
}
let bb = {...aa};
bb.address.city = 'shenzhen';
console.log(aa.address.city); // shenzhen
9.多维数组扁平化
var arr = [1, 2, [3, 4, [5, 6, 7]], 9, [10, 11]]
function steamroller(arr) {
while (arr.some(item => Array.isArray(item))) {
// arr = [].concat.apply([], arr) //es5
arr = [].concat(...arr) //es6
}
return arr
}
console.log(steamroller(arr))
10.将伪数组转化为真正的数组
部署了Iterator(遍历器) 接口可以直接转数组
let nodelist = document.querySelectorAll('div')
let aa = [...nodelist]
// aa.map((item) => {
// return console.log(item)
// })
console.log(aa) // nodelist其实是对象,转化为数组
console.log(Array.from(nodelist)) //[div, div]
console.log(nodelist)
没有部署了Iterator接口的对象不可以直接转数组
let obj = {
name: 'zhangsan',
age: 24,
address: 'beijing',
}
let arr = [...obj]
console.log(arr) //不可以转数组