空值合并运算符 ??
空值合并运算符??是一个逻辑操作符, 当左侧的操作数为null或者undefined时, 返回右侧操作数, 否则返回左侧操作数。
-
左侧操作符是null。
const data = null;
const str = data?? '我是一个空值'
console.log(str) //我是一个空值
-
左侧操作符是undefined
const data = undefined;
const str = data?? '我是一个空值'
console.log(str) //我是一个空值
-
左侧操作符是其他
const data = '哈哈';
const str = data?? '我是一个空值'
console.log(str) //哈哈
-
为变量赋默认值
由于 ||
是一个布尔逻辑运算符, 左侧的操作数会被强制转化为布尔值
用于求值。 任何假值(0
,null
, NaN
, ''
, undefined
)都不会被返回。 这导致如果使用 0,'', NaN
做为有效值, 就不会正常返回。
空值合并操作符可以避免这种陷阱,其只在第一个操作数为null
或 undefined
时(而不是其它假值)返回第二个操作数:
let str = '';
let str2 = str || 'Hello world';
console.log(str2); // Hello world
let str3 = str ?? 'Hi neighborhood';
console.log(str3); // ''
逻辑空赋值 ??=
逻辑空运算符x??=y
仅在x 是 null
或者undefined
时对其赋值。
const p = {
name:'Iric'
}
p.name??='张三'
console.log(p.name) //Iric
p.age??= 23
console.log(p.age) //23
逻辑空赋值的语法短路也意味着 x ??= y
等价于:x ?? (x = y)
;
链判断运算符 ?.
可选链操作符?.
允许读取位于对项链深处的属性的值, 而不必明显验证链中的每个引用是否有效。?.
操作符的功能类似.链式操作符。 不同之处在于, 在引用为(null
和undefined
)的情况下不会引起错误。 改表达式的短路返回值时undefiende。
const p = {
name:'Iric',
friends:{
name:'Lisa'
}
}
const name = p.friends?.name;
console.log(name)//Lisa
const age = p.friends?.age;
console.log(age) /undefined
链判断运算符?.
有三种写法。
obj?.prop
// 对象属性是否存在obj?.[expr]
// 同上func?.(...args)
// 函数或对象方法是否存在
a?.b
// 等同于
a == null ? undefined : a.b
a?.[x]
// 等同于
a == null ? undefined : a[x]
a?.b()
// 等同于
a == null ? undefined : a.b()
a?.()
// 等同于
a == null ? undefined : a()
(1)短路机制
本质上,?.
运算符相当于一种短路机制,只要不满足条件,就不再往下执行。
a?.[++x]
// 等同于
a == null ? undefined : a[++x]
上面的代码, 如果a
是undefined
或者null
, 那么x
就不会递增运算, 也就是说, 链判断运算符一旦为真, 右侧的表达式就不会在求值。
(2)括号的影响
如果属性链有圆括号, 连判断运算符对圆括号外部没有影响, 只对圆括号内部有影响。
(a?.b).c
//等价于
(a == null? undefined: a.b).c
上面代码中, ?.
对圆括号外部没有影响, 不管a
对象是否存在, 圆括号后面的.c
总是会执行。
一般来说, 使用?.运算符的场合, 不应该使用圆括号。
指数运算符 **
指数运算符(**
):这个运算符的一个特点是右结合
,而不是常见的左结合
。多个指数运算符连用时,是从最右边开始计算的。
// 相当于 2 ** (3 ** 2)
2 ** 3 ** 2
指数运算符可以与等号结合,形成一个新的赋值运算符(**=
)。
let a = 1.5;
a **= 2;
// 等同于 a = a * a;
let b = 4;
b **= 3;
// 等同于 b = b * b * b;
总结
这三个运算符||=
、&&=
、??=
相当于先进行逻辑运算
,然后根据运算结果,再视情况进行赋值运算
// 或赋值运算符
x ||= y
// 等同于
x || (x = y)
// 与赋值运算符
x &&= y
// 等同于
x && (x = y)
// Null 赋值运算符
x ??= y
// 等同于
x ?? (x = y)