或者使用三元运算符?:,判断一个对象是否存在。

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

    这样的层层判断非常麻烦,因此 引入了“链判断运算符”(optional chaining operator)?.,简化上面的写法。

    1. const firstName = message?.body?.user?.firstName || 'default';
    2. const fooValue = myForm.querySelector('input[name=foo]')?.value

    上面代码使用了?.运算符,直接在链式调用的时候判断,左侧的对象是否为nullundefined。如果是的,就不再往下运算,而是返回undefined

    链判断运算符有三种用法。

    • obj?.prop // 对象属性
    • obj?.[expr] // 同上
    • func?.(...args) // 函数或对象方法的调用

    下面是判断对象方法是否存在,如果存在就立即执行的例子。

    上面代码中,iterator.return如果有定义,就会调用该方法,否则直接返回undefined

    对于那些可能没有实现的方法,这个运算符尤其有用。

    1. if (myForm.checkValidity?.() === false) {
    2. // 表单校验失败
    3. return;

    下面是这个运算符常见的使用形式,以及不使用该运算符时的等价形式。

    1. a?.b
    2. // 等同于
    3. a == null ? undefined : a.b
    4. a?.[x]
    5. // 等同于
    6. a == null ? undefined : a[x]
    7. a?.b()
    8. // 等同于
    9. a?.()
    10. // 等同于
    11. a == null ? undefined : a()

    上面代码中,特别注意后两种形式,如果a?.b()里面的a.b不是函数,不可调用,那么a?.b()是会报错的。a?.()也是如此,如果a不是nullundefined,但也不是函数,那么会报错。

    使用这个运算符,有几个注意点。

    (1)短路机制

    上面代码中,如果aundefinednull,那么x不会进行递增运算。也就是说,链判断运算符一旦为真,右侧的表达式就不再求值。

    (2)delete 运算符

    1. delete a?.b
    2. // 等同于
    3. a == null ? undefined : delete a.b

    上面代码中,如果aundefinednull,会直接返回undefined,而不会进行delete运算。

    如果属性链有圆括号,链判断运算符对圆括号外部没有影响,只对圆括号内部有影响。

    1. (a?.b).c
    2. // 等价于
    3. (a == null ? undefined : a.b).c

    上面代码中,?.对圆括号外部没有影响,不管a对象是否存在,圆括号后面的.c总是会执行。

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

    (4)报错场合

    以下写法是禁止的,会报错。

    (5)右侧不得为十进制数值

    为了保证兼容以前的代码,允许foo?.3:0被解析成foo ? .3 : 0,因此规定如果?.后面紧跟一个十进制数字,那么不再被看成是一个完整的运算符,而会按照三元运算符进行处理,也就是说,那个小数点会归属于后面的十进制数字,形成一个小数。