JS 可选链与双问号

为了测试新语法,可以打开参考资料中的 MDN 链接,其中有在线编辑器,或者使用 Chrome console

前言

公司的代码中已经开始有 ???. 了,刚看到这些代码有点摸不着头脑,看完 MDN 也就了解个大概。

担心细枝末节被我忽略了,得空来整理一下

1. 可选链(Optional chaining) ?.

以前我们可能会写这样的代码:

const a = {
    b: {
        c: {
            d: [1]
        }
    }
}

const data = (a && a.b && a.b.c && a.b.c.d) || []

即为了确保不会报 cant read property from property, 我们需要添加很长的判断条件

有了,可选链之后,你可以这样:

示例一:

a.e.f  // 报错,a.e 为 undefined,取 undefined.f 会报错

a.e?.f // undefined, 即,使用可选链之后,不会报错

a?.e.f
// 报错,即,a?.e 只能保证即使 a 为 undefined,a.e 也不会报错
// 但是不能阻止 a.e.f 报错

// 但是
console.log(a?.e.f.d.g)   // 会报错,a?.e 为 undefined, f 不是 undefined 的属性
console.log(a.e.f?.d.g)   // 会报错,a.e 为 undefined, f 不是 undefined 的属性
console.log(a.e?.f.d.g)  // 这样居然不会报错???为什么


// 针对以上会报错的两种情况,可以使用多个可选链叠加一起使用
console.log(a?.e?.f?.d?.g)   // 不会报错

示例二:

const a = null;
a.b;  // 报错,b 不是 null 的属性

a?.b  // 不会报错,打印 undefined

a?.b.c.d.e.f  // 打印 undefined, 不会报错, 为什么 ???

示例三, 可选链与函数调用:

语法 func?.(args)

const a = {
    b: {
        c: {
            d: [1]
        }
    }
}
console.log(a.e?.())  // 不会报错
console.log(a.e?.b())  // 同样不会报错


const a = {
    e: {
        c: {
            d: [1]
        }
    }
}
console.log(a.e?.())  // 会报错,a.e 不是函数


就是说,通过可选链,如果 a.e 为 null 或者 undefined,调用a.e?.() 不会报错。

但是,如果存在 a.e, 但是 a.e 不是函数,那么还是会正常报错

总结 可选链操作符使得:

  • 当对象为 null 或者 undefined 时,读取对象的属性不会报错。

  • 当函数为 null 或者 undefined 时, 调用该函数不会报错

  • 如果遇到连续的属性访问时,可以使用多个可选链(坏处可能是被 babel 编译之后,代码量变多)

2. 双问号(Nullish coalescing operator) ??

left ?? right

当 left 为 null 或者 undefined 时,返回右边的值.

注意:|| 不一样的是,如果 left 为 '' 或者 0 或者 false, ?? 依然会返回 left 的值:

const foo = null ?? 'default string';
console.log(foo);   // 返回右边的值 default string

const foo = null || 'default string';
console.log(foo);   // 返回右边的值 default string

// 遇到 false,0,'', NaN 时不一样
const baz = 0 ?? 42;
console.log(baz);   // 返回左边的值,0

const baz = 0 || 42;
console.log(baz);   // 返回右边的值,42

同样,它也有短路操作

function A() { console.log('A was called'); return null;}
function B() { console.log('B was called');}

console.log( A() ?? B() );
// A 函数执行,返回 undefined,
// ?? 认为 undefined 是 "false" 值,此时会继续计算 B 函数
// 最终返回 undefined(B 函数没有返回值,则默认为 undefined)

// 短路
function A() { console.log('A was called'); return false;}
function B() { console.log('B was called');}

console.log( A() ?? B() );
// A 函数执行,返回 false,
// ?? 认为 false 是 "true" 值,不再计算 C 函数, 最终返回 false

3. 可选链与双问号

可选链允许使用 undefined?.xxx() 而不报错,当然不报错是一回事,它的返回结果还是 undefined.

因此,这种时候可以再配合双问号来设置默认值:

undefined?.xxx()  ?? '123'  // 返回 123

参考资料

Last updated