TL;TR
使用? 检查表达式中的non-undefined、not-null 值,如果发现某个值是其中之一,则链会中断并返回undefined。
需要注意的重要一点是它仅 防范undefined 和null 值而不是falsy 值,即它仍然会传递其他虚假值,例如NaN 或 ""。
详细说明
让我们从引用MDN开始
可选的链接运算符提供了一种简化访问的方法
当引用可能时,通过连接的对象获取值
或函数可能未定义或为空。
考虑这样一个对象:
var obj = {
a: {
b: 1
},
}
现在要验证obj、obj 的属性a,然后验证a 的属性b 不是undefined 和null,您可能需要执行以下操作:
obj && obj.a && obj.a.b
可选链接为您提供了一个替代方案。你可以这样做:
obj?.a?.b
现在,假设a 恰好是一个函数,它返回一个具有属性b 的对象,该对象包含一个值1。像这样的:
var obj = {
a: function{
return {b:1}
},
}
那么,对于深度嵌套的 b,您现在将如何验证 obj 及其字段?好吧,你可以这样做:
obj && obj.a && typeof obj.a === 'function' && obj.a() && obj.a().b
或者你可以简单地做
obj?.a()?.b
这只是意味着检查obj是否为非未定义和非空,(如果是)然后检查obj?.a()是否相同,(如果是那么)执行obj的方法a()。如果执行后该方法返回一个值(不是undefined 或null),则从中获取属性b 的值。
在此检查期间的任何时候,如果发现一个值是undefined 或null,只需断开链并返回undefined
但是,如果a 不是在前面的表达式中使用typeof obj.a === 'function' 检查过的函数,这将失败。
另外,请注意,此时如果obj.a() 碰巧返回,比如“baz”,它将被执行为
"baz".b 会给你undefined。
有了这些知识,我们可以很容易地破译这个表达式:
obj.a?.().b
它检查obj.a 是否为non-undefined、not-null。如果是,则执行 obj.a()(请注意,如果 obj.a 不是函数而是返回数字 5,则会抛出错误)
如果obj.a() 发生成功执行,则将检查返回值的.b。
现在这是剩下的
obj.a?.()?.b
嗯,这也像我们之前的执行一样执行:
检查obj.a 是否为not-null 和non-undefined。如果是,请执行obj.a。如果那也是non-null和non-undefined,执行obj.a()等等。
如果在检查时的任何时候,发现值是null 或undefined,链就会中断。
非常重要的一点要注意,我们的操作符 ? 只防范 undefined 和 null 而不是防范其他 falsy 值。
考虑一下
var a = undefined
var myVal = a?.details.b;
alert(a) //will return undefined
var a = ""
var myVal = a?.details.b;
alert(a) //Our guard fails us here and simply throws an error