一、扩展运算符
扩展运算符(spread)是三个点...
,好比rest参数的逆运算,将一个数组转化为用逗号分隔的参数序列
console.log(...[1, 2, 3]); // 1 2 3
console.log(1, ...[2, 3, 4], 5); // 1 2 3 4 5
扩展运算符主要用于函数调用
function fn(arr, ...items) {
console.log(items);
arr.push(...items);
console.log(arr);
}
fn([], 1, 2);
function add(a, b) {
return a + b;
}
const arr = [1, 2];
console.log(add(...arr));
-
替代函数的apply方法
由于扩展运算符可以展开数组,所以不再需要apply()方法将数组转换为函数的参数;
// ES5的方案
function fn(a, b, c) {
console.log(a + b + c);
}
const arr = [1, 2, 3];
// fn(arr);
fn.apply(null, arr);
// ES6的方案
function fn(a, b, c) {
console.log(a + b + c);
}
const arr = [1, 2, 3];
fn(...arr);
-
扩展运算符的应用
1. 复制数组
数组是复杂数据类型,直接复制的话,只是复制了指向底层数据结构的指针,而不是克隆一个全新的数组;
// ES5复制的是指针
let arr1 = [1, 2, 3];
let arr2 = arr1;
arr1[0] = 4;
console.log(arr2); // [4, 2, 3]
// 通过concat方法,实现了深拷贝
let arr1 = [1, 2, 3];
let arr2 = arr1.concat();
arr1[0] = 4;
console.log(arr2); // [1, 2, 3]
// ES6给出了更简单的做法
let arr1 = [1, 2, 3];
let arr2 = [...arr1];
arr1[0] = 4;
console.log(arr2); // [1, 2, 3]
2. 合并数组
扩展运算符提供了数组合并的新写法
// ES5的方案
let arr1 = ["a", "b", "c"];
let arr2 = ["d", "e", "f"];
let arr3 = arr1.concat(arr2);
console.log(arr3);
// ES6的方案
let arr1 = ["a", "b", "c"];
let arr2 = ["d", "e", "f"];
let arr3 = [...arr1, ...arr2];
console.log(arr3);
3. 字符串转为数组
扩展运算符还可以将字符串转为真正的数组;
// ES5的方案
let str = 'hello';
str = str.split('');
console.log(str);
// ES6的方案
let str = 'hello';
console.log([...str]);
4. 类数组转化为数组
function fn() {
console.log(arguments);
console.assertl([...arguments]);
}
fn(1, 2, 3);
二、指数运算符
- 指数运算符:
**
console.log(2**2); // 4
console.log(3**4); // 3 * 3 * 3 * 3 = 81
console.log(Math.pow(3, 4));
- 指数运算符是右结合,不是左结合。多个指数运算符连用时,是从最右边开始计算的;
console.log(2 ** 3 ** 2); // 512
let a = 1.5;
console.log((a **= 3)); // a = a*a*a
三、链判断运算符
如果读取对象内部的某个属性,往往需要判断一下,属性的上层对象是否存在。
因此 ES2020 引入了“链判断运算符”(optional chaining operator)?.
直接在链式调用的时候判断,左侧的对象是否为null
或undefined
。如果是的,就不再往下运算,而是返回undefined
示例:
let rst = {
code: 200,
data: {
msg: "ok",
info: {
type: 1,
data: {
id: null,
title: "靴子"
}
}
}
}
// let t= rst.data.info.data.title;
// let t = rst.data.info.data.title || "帽子";//error
// let t = (rst || rst.data || rst.data.info || rst.data.info.title) || "帽子";
// let t = rst?.data?.info?.data?.title || "帽子"
// console.log(t);
四、Null 判断运算符
读取对象属性的时候,如果某个属性的值是null
或undefined
,有时候需要为它们指定默认值。常见做法是通过||
运算符指定默认值。
ES2020 引入了一个新的 Null 判断运算符??
。它的行为类似||
,但是只有运算符左侧的值为null
或undefined
时,才会返回右侧的值。
示例:
let rst = {
code: 200,
data: {
msg: "ok",
info: {
type: 1,
data: {
id: null,
title: "靴子"
}
}
}
}
// "" null undefined 0
// let t=rst.data.info.data.id || 100;
//只有结果为null或undefined时,才生效
// let t=rst.data.info.data.id ?? 100;
let t = rst?.data?.info?.data?.title ?? "帽子"
console.log(t);
五、逻辑赋值运算符
- 在ES2021引入了三个新的逻辑赋值运算符,将逻辑运算符与赋值运算符进行结合;
// 或赋值运算符
x ||= y
// 等同于
x || (x = y)
// 与赋值运算符
x &&= y
// 等同于
x && (x = y)
// null赋值运算符
x ??= y
// 等同于
x ?? (x = y)
这三种运算符相当于先进行逻辑运算,然后根据运算结果,再试情况进行赋值运算。
它们的一个用途,就是为变量进行逻辑运算,然后根据运算结果,再试情况进行赋值运算;
let o = {
// id: ''
}
// 老的写法
o.id = o.id || 1;
o.num ||= 2;
console.log(o.id); // 1
console.log(o.num); // 2