?.
)读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。如果某一引用无效(null
或 undefined
)不会引起错误,而是返回 undefined
。
const a = {id:1, name:'张三'};
console.log(a?.age);
// 多个可选链
let res = a?.name?.firstName;
// 可选链表达式
let res = a?.['na' + 'me'];
// 访问数组
let arrItem = arr?.[13];
将简化判断对象是否包含某一成员,如果包含访问该成员的某些属性或方法。
??
)空值合并操作符是一个逻辑操作符,当左侧的操作数为 null
或者 undefined
时,返回其右侧操作数,否则返回左侧操作数。它与逻辑或操作符类似,但是某些情况下(例如左侧值为 ''
即空字符串,或数字 0,或布尔值 false),会意外的返回右侧操作数。而空值合并操作符只有在左侧为空(null
或者 undefined
)时返回右侧。
let a = 0 || 123; // 123
let a = 0 ?? 123; // 0
let a = false ?? 123; // false
将简化某些可能需要与 0 或 false 等合并时进行的判断,减少意外。也可以和可选链合用,达成访问属性为空时返回默认值的操作。
let a = person?.name ?? '匿名';
??=
)类似于空值合并操作符,在运算符左侧为空( null
或者 undefined
) 时,将右侧赋值给左侧
let b = 'hello';
let a = 0;
let c = null;
a ??= b; // a === 0
c ??= b; // c === 'hello'
!.
)这是TypeScript的语法,叫非空断言操作符**(non-null assertion operator)**,和?.相反,这个符号表示对象后面的属性一定不是null或undefined。
let a = {id:1, name='张三'};
console.log(a!.id)
...
)在 js 中,扩展运算符**(spread)和剩余运算符(rest)均是三个点(...
)**。
扩展运算主要作用是将数组或对象拆分为多个参数序列,它会调用默认的 Iterator
接口
// 扩展数组
const test = (a, b, c) => {
console.log(a) // 1
console.log(b) // 2
console.log(c) // 3
}
let arr = [1, 2, 3];
test(...arr);
// 将一个数组扩展到另一个数组中
let arr1 = [1, 2, 3];
let arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
let arr3 = [4, ...arr1, 5]; // [4, 1, 2, 3, 5]
// 将字符串扩展为数组
let str = 'hello';
let arr4 = [...str]; // ['h', 'e', 'l', 'l', 'o']
扩展运算也适用于对象
let a = {id:1, name='张三'};
let b = {...a};
使用对象的扩展和直接赋值是有区别的,直接赋值其实是将原对象的内存地址引用进行赋值,而扩展某种程度上是创建了一个新对象。需注意扩展并不完全等同于深度复制,因为扩展只是将一级属性进行复制,如果其中有对象的话,还是赋值此对象的内存地址引用。
剩余运算和扩展运算正好相反,是将一个值序列组合合并成一个数组
// 当函数参数个数不固定,可以使用剩余运算合并成一个数组
const f1 = (...args) => {
console.log(args) // [1, 2, 3]
}
f1(1, 2, 3);
// 部分参数不固定
const f2 = (item, ...args) => {
console.log(item) // 1
console.log(args) // [2, 3]
}
f2(1, 2, 3);
解构也有叫做拆包,就是将一个对象(或数组,因为js中数组也是对象)拆分开来。
let arr = [1, 2, 3];
// 将数组元素依次赋值给单个变量
let [a, b, c] = arr; // 相当于 a=1,b=2,c=3
// 变量个数小于数组元素个数无影响
let [a, b] = arr;
// 变量个数大于数组元素个数,多出来的赋值为 undefined
let [a, b, c, d] = arr; // d为undefined
// 解构时也可以使用默认值
let [a, b, c = 33, d = 44] = arr; // c的值还是3,d的值是44
// 只取部分元素可以使用占位
let [, b] = arr; // b为2
let [a, ...b] = arr; // 配合剩余运算, a为1,b为[2,3]
需要注意的是,扩展运算符(剩余运算) ...
只能出现在解构语法的最后。
对象解构时,必须名称一致,对顺序可以没有要求。
let obj = {a: 1, b: 2};
let {x, y} = obj; // x和y均为 undefined
let {a, b} = obj; // a为1,b为2
let {b, a} = obj; // 同上
对象的解构中,还能为变量重命名
let obj = {a: 1, b: 2};
let {a: x, b: y} = obj;
// a , b 会报未定义的错
// x为1,y为2
配合扩展运算符获取对象部分属性
let obj = {a: 1, b: 2, c: 3};
let {a, ...b} = obj;
// a为1
// b为{b: 2, c: 3}
使用已有变量进行解构
let x, y;
({a: x, b: y} = {a: 1, b: 2, c: 3});
// x为1
// y为2
需注意的是,因为 {}
中的内容会被部分浏览器当成一个代码块,所以需要使用 ()
括号包裹。
对象的解构使用默认值
let x, y, z;
({a: x, b: y, d: z = {num: 1}} = {a: 1, b: 2, c: 3});
// x为1
// y为2
// z为 {num: 1}