先定义操作符(??)(缺值合并)

本文最后更新于:21 分钟前

先定义操作符(??)(缺值合并)

先定义(first-defined)操作符**??**求值其先定义的操作数,如果其左操作数不是nullundefined,就返回该值。否则,它会返回右操作数的值。
&&||操作符类似,??是短路的:它只在第一个操作数求值为null或undefined时才会求值第二个操作数。
如果表达式a没有副效应,那么表达式a ?? b等价于:

1
( a !== null && a !== undefined ) ? a : b

??是对||的一个有用的替代,适合选择先定义的操作数,而不是第一个为真值的操作数。尽管||名义上是个逻辑或操作符,习惯上也会使用它选择第一个非假值操作数,比如:

1
2
3
//如果maxWidth是真值,就使用它;否则,看看preferences
//对象。如果preferences里也没有真值,就使用硬编码的常量
let max = maxwidth || preferences.maxwidth || 500;

这种习惯用法的问题在于,0、空字符串和false都是假值,但这些值在某些情况下是完全有效的。对上面的代码示例来说,maxWidth如果等于0,该值就会被忽略。如果我们把||操作符改为??,那么对这个表达式来说,0也会成为有效的值

1
let max = maxwidth ?? preferences.maxwidth ?? 500;

其中??的第一个操作数都是假值。如果这个操作数是假值但有定义,??仍然返回这个值。只有当第一个操作数“缺值”(nullish)时(即null或undefined),这个操作符才会求值并返回第二个操作数:

1
2
3
4
5
6
7
8
9
10
11
let options={
tiem:0,
title:'',
verbose:false,
n:null
}

options.title ?? 'untitled' //'' 在对象中有定义
options.verbose ?? true //false 在对象中有定义
options.quite ?? false //false 属性没有定义
options.n ?? 10 //10 属性值为null

注意,如果我们使用||而不是??,这里的timeout、title和verbose表达式会求值为不同的结果。

??操作符与&&||操作符类似,但优先级并不比它们更高或更低。如果表达式中混用了??和它们中的任何一个,必须使用圆括号说明先执行哪个操作:

1
2
3
(a ?? b) || c  //??先执行,然后执行
a ?? (b || c) //||先执行,然后执行??
a ?? b || c //SyntaxError:必须有圆括号