js 可选链(?.)、空值合并(??)、与(&&)、或(||)、三目运算符(?)详解

367 阅读3分钟

回顾传统 || 返回默认值做法

const response = {
    nullValue: null,
    height: 400,
    animationDuration: 0,
    headerText: '',
    showSplashScreen: false
};
// 当 || 左边为 falsy 时返回右边表达式的值,左边为truthy则返回左边表达式的值 (不明白truthy和falsy的可以看我的另外一篇文章)
const test = response.undefinedValue || '默认值'
const test2 = response.nullValue || '默认值'

但是当值为0,'',false等时,也会返回默认值。

const headerText = response.headerText || 'Hello, world!'; // '' is falsy, result: 'Hello, world!'
const animationDuration = response.animationDuration || 300; // 0 is falsy, result: 300
const showSplashScreen = response.showSplashScreen || true; // false is falsy, result: true

??(Nullish coalescing Operator 空值合并运算符)就是用来解决上述问题的。

Base case. If the expression at the left-hand side of the ?? operator evaluates to undefined or null, its right-hand side is returned.

简单来说就是:当 ?? 左边表达式的值为 null 或 undefined 时返回右边表达式的值,否则返回左边表达式的值。

const response = {
    nullValue: null,
    height: 400,
    animationDuration: 0,
    headerText: '',
    showSplashScreen: false
};

const undefinedValue = response.undefinedValue ?? 'some other default'; // result: 'some other default'
const nullValue = response.nullValue ?? 'some other default'; // result: 'some other default'
const headerText = response.headerText ?? 'Hello, world!'; // result: ''
const animationDuration = response.animationDuration ?? 300; // result: 0
const showSplashScreen = response.showSplashScreen ?? true; // result: false

?. Optional Chaining 可选链运算符

以前我们可以使用 && 可以防止当 user.address 为 undefined 或 null 时取值报错。

var street = user.address && user.address.street;

或者在读取节点的时候做判断 (节点有可能为 null)

var fooInput = myForm.querySelector('input[name=foo]')
var fooValue = fooInput ? fooInput.value : undefined

可选链运算符 ?. 提供了另外的选择

var street = user.address?.street // 当 user.address 为 undefined 或 null 时则返回 undefined,否则继续往下取 user.address.street
var fooValue = myForm.querySelector('input[name=foo]')?.value

?. 基本使用

If the operand at the left-hand side of the `?.` operator evaluates to undefined or null, the expression evaluates to undefined. Otherwise the targeted property access, method or function call is triggered normally.

Here are basic examples, each one followed by its desugaring. (The desugaring is not exact in the sense that the LHS should be evaluated only once and that `document.all` should behave as an object.)
a?.b                          // 如果 a 为 null/undefined 返回 undefined, 否则 `a.b`.
a == null ? undefined : a.b   // == 判断时 null == undefined

a?.[x]                        // undefined if `a` is null/undefined, `a[x]` otherwise.
a == null ? undefined : a[x]

a?.b()                        // undefined if `a` is null/undefined
a == null ? undefined : a.b() // throws a TypeError if `a.b` is not a function
                              // otherwise, evaluates to `a.b()`

a?.()                        // undefined if `a` is null/undefined
a == null ? undefined : a()  // throws a TypeError if `a` is neither null/undefined, nor a function
                             // invokes the function `a` otherwise

?. 短路机制

?. 的左边(a) 的值为 undefined 或 null ,++x 不会执行,这叫做短路。

a?.[++x]         // `x` is incremented if and only if `a` is not null/undefined
a == null ? undefined : a[++x]

括号的影响

(a?.b).c // 等价于 (a == null ? undefined : a.b).c 上面代码中,?. 对圆括号外部没有影响,不管 a 对象是否存在,圆括号后面的 .c 总是会执行。

一般来说,使用 ?. 运算符的场合,不应该使用圆括号。

连续使用 ?.

a?.b[3].c?.(x).d
// 相当于 a == null ? undefined : a.b[3].c == null ? undefined : a.b[3].c(x).d

?. 可选删除

delete a?.b
a == null ? true : delete a.b

不能使用 ?. 的情况

  • optional construction: new a?.()
  • optional template literal: a?.`string`
  • constructor or template literals in/after an Optional Chain: new a?.b()a?.b`string`

The following is not supported, although it has some use cases; see Issue #18 for discussion:

  • optional property assignment: a?.b = c

The following are not supported, as it does not make much sense, at least in practice; see Issue #4 (comment):

  • optional super: super?.()super?.foo
  • anything that resembles to property access or function call, but is not: new?.targetimport?.('foo'), etc. ?? ?. 结合使用
// response 为 undefine 或 null 或者 response.animationDuration 为 undefined 或 null时,返回 300
const animationDuration = response?.animationDuration ?? 300;

&& 逻辑与运算符

expr1 && expr2

如果 expr1 隐式转换为 Boolean 类型后为 true,也就是 expr1 为 truthy, 返回表达式 expr2; 否则 返回表达式 expr1。假如 expr1 为 falsy ,expr2 不会执行,这就是短路机制。

&& 逻辑与运算符 和 || 逻辑或运算符的优先级

true || false && false      // returns true, 因为 && 优先级比 || 高,先执行 &&
(true || false) && false    // returns false, because operator precedence cannot apply

&& 比 || 优先级高

|| 逻辑或运算符

expr1 || expr2

当 expr1 返回的值为 truthy, 则直接返回 expr1 , expr2 不执行;否则,返回 expr2

&& || 互相转换

// && 转换为 ||
bCondition1 && bCondition2 === !(!bCondition1 || !bCondition2)
// || 转为 &&
bCondition1 || bCondition2 === !(!bCondition1 && !bCondition2)

? : 条件(三元)运算符

condition ? exprIfTrue : exprIfFalse

当 condition 为 truthy 时,返回 exprIfTrue;否则返回 exprIfFalse

var age = 26;
var beverage = (age >= 21) ? "Beer" : "Juice";
console.log(beverage); // "Beer"

简化 if 语句

function example() {
    return condition1 ? value1
         : condition2 ? value2
         : condition3 ? value3
         : value4;
}

// Equivalent to (相当于):

function example() {
    if (condition1) { return value1; }
    else if (condition2) { return value2; }
    else if (condition3) { return value3; }
    else { return value4; }
}