1.扩展运算符
扩展运算符(spread)是三个点(…)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
- 扩展运算符与正常的函数参数可以结合使用,非常灵活。
[1, 3, 4, ...[5, 6, 7, 8, 9], 7, 54, 232];
//[ 1, 3, 4, 5, 6, 7, 8, 9, 7, 54, 232 ]
- 用于函数调用:
let arr = [];
function testFn(a,...items){
arr.push(...items);
}
testFn(1,2,3,4,5,6,78)
//arr: [ 2, 3, 4, 5, 6, 78 ]
参数中 testFn(a,…items) 使用了 reset 参数,调用时 arr.push(…items) 使用了 扩展运算符
有了扩展运算符,这里push 的时候我们就不用写循环啦
- 如果扩展运算符后面是一个空数组,则不产生任何效果
[...[],1];// [1]
- 扩展运算符后面还可以放置表达式
let x = 0;
const arr = [
...(x > 0 ? ['a'] : []),
'b',
];
表达式得出的结果必须是数组,不然就会报错 (这样说对不对噢)
注:(…[items]) 这种在圆括号中使用扩展运算符只能是在函数调用的时候,否则就会进行报错
Unexpected number
- 替代apply方法 (仅仅只是替代它传递数组做参数的这个功能)
先康康apply 方法:
1.Function.apply(obj,args)方法能接收两个参数
2.obj:Function 中的this 绑定为 obj
3.args:这个是数组,它将作为参数传给Function(args–>arguments)
试试:
let obj = {
name: 'heihei'
}
function Factory(name) {
console.log(this);// obj
console.log(arguments);//[Arguments] { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }
this.name = name;
}
Factory.apply(obj, [1, 2, 3, 4, 5])
这里有个问题: apply() 的第二个参数必须是数组,否则就会报错:
CreateListFromArrayLike called on non-object
对比:
// ES5 的写法
Math.max.apply(null, [14, 3, 77])
// ES6 的写法
Math.max(...[14, 3, 77]);
这样一看,果然是更加简便了,也更容易理解
扩展运算符的应用
- 复制数组
let arr = [1, 2, 3, 4, 5, 6];
let arrCopy = [...arr];
arrCopy[1] = 999;
console.log(arr); // [1, 2, 3, 4, 5, 6]
console.log(arrCopy);//[ 1, 999, 3, 4, 5, 6 ];
当然,也可以复制对象
let obj = { firstName: 'xm', lastName: 'z' };
let newObj = {...obj };
newObj.firstName = 'newName';
console.log(newObj);//{ firstName: 'newName', lastName: 'z' }
console.log(obj);//{ firstName: 'xm', lastName: 'z' }
注:仅仅适合一层的数组,对象 ,如果数组或者对象内部又引用了其他的对象或者数组,那么对于这一层来说就仍然是浅拷贝,深浅拷贝专场 (这里有链接)
- 合并数组
//使用concat
let arr = [1, 2, 3, 4];
let arr2 = [5, 6, 7, 8];
arr2 = arr2.concat(arr);// [5,6,7,8,1,2,3,4]
//使用扩展运算符
let arr3 = [...arr,...arr2];//[ 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4 ];
能少敲好几个单词 [doge]
- 结合结构赋值
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
const [first, ...rest] = [];
first // undefined
rest // []
const [first, ...rest] = ["foo"];
first // "foo"
rest // []
- 将字符串转为数组,这个做法是不是十分熟悉
let str = 'helloWorld';
let arr = str.split('');//[ 'h', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd' ]
使用扩展运算符:
let arr = [...str];//[ 'h', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd' ]
如果仅仅是将字符串转换成数组,则两种方法都适用,如果是需要以特定的字符对字符串进行分割,则 spllit() 适用
还有另一个好处:能够正确识别四个字节的 Unicode 字符
'x\uD83D\uDE80y'.length // 4
[...'x\uD83D\uDE80y'].length // 3
let str = 'x\uD83D\uDE80y';
str.split('').reverse().join('')
// 'y\uDE80\uD83Dx'
[...str].reverse().join('')
// 'y\uD83D\uDE80x'
凡是涉及到操作四个字节的 Unicode 字符的函数,都有这个问题。因此,最好都用扩展运算符改写
- 任何定义了遍历器(Iterator)接口的对象(参阅 Iterator 一章),都可以用扩展运算符转为真正的数组。
Number.prototype[Symbol.iterator] = function*() {
let i = 0;
let num = this.valueOf();
while (i < num) {
yield i++;
}
}
console.log([...5]) // [0, 1, 2, 3, 4]
Map
let map = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);//Map { 1 => 'one', 2 => 'two', 3 => 'three' }
let arr = [...map.keys()]; // [1, 2, 3]
//keys方法可以返回一个Map对象的键的遍历器对象。
Generator 函数 [Generator 函数详解]
let go = function*(){
yield 1;
yield 2;
yield 3;
};
[...go()];//[1,2,3]
Generator 函数 运行后,返回一个遍历器对象,因此也可以使用扩展运算符