我一直在使用JavaScript编写类似以下的代码:
if (params && params.profile && params.profile.address && params.profile.address.default)
这里需要检查每个可选项,这样做很繁琐。在JavaScript中是否有一种更好的方式,类似于Swift处理可选项的方式,例如:
if let checked = params?.profile?.address?.default?
我一直在使用JavaScript编写类似以下的代码:
if (params && params.profile && params.profile.address && params.profile.address.default)
这里需要检查每个可选项,这样做很繁琐。在JavaScript中是否有一种更好的方式,类似于Swift处理可选项的方式,例如:
if let checked = params?.profile?.address?.default?
使用与 Swift 相同的 ?.
语法,可将可选链添加到语言中,因此我建议您采用这种方式,除非您需要支持旧版浏览器。
如果您需要支持旧版浏览器,我已经编写了一个处理函数:
function getSafe (func) {
try {
return func()
} catch (e) {
if (e instanceof TypeError) {
return undefined
} else {
throw e
}
}
}
像这样调用:
if (getSafe(() => params.profile.address.default))
这段代码之所以能够正常工作,是因为将其封装在一个匿名函数中,在try/catch块中才被执行,如果任何父级属性未定义,则会触发try/catch块并返回undefined
。
检查e
是否为TypeError
可以防止它吞噬函数可能抛出的任何其他错误,因此还可以按需处理这些错误。如果想在任何错误时都返回undefined
,可以删除该部分:
function getSafeNoErrors (func) {
try {
return func()
} catch {
return undefined
}
}
在原生JS中没有这样的运算符。
然而,有一个Babel插件可以实现这一点,请查看https://github.com/davidyaha/ecmascript-optionals-proposal
此外,请参考ES6/2015中的Null-safe属性访问(和条件赋值)来获取更多参考资料。
现在你可以直接使用?.
(可选链)内联方式安全地测试存在性。所有现代浏览器都支持它。
如果属性存在,?.
将继续进行下一个检查或返回有效值。任何故障将立即停电并返回undefined
。
const example = {a: ["first", {b:3}, false]}
example?.a // ["first", {b:3}, false]
example?.b // undefined
// Dynamic properties ?.[]
example?.a?.[0] // "first"
example?.a?.[1]?.a // undefined
example?.a?.[1]?.b // 3
// Functions ?.()
null?.() // undefined
validFunction?.() // result
(() => {return 1})?.() // 1
// DOM Access
domElement?.parentElement?.children?.[3]?.nextElementSibling
如果您未检查一个情况,则左侧属性必须存在。如果不存在,将会抛出异常。
example?.First // undefined
example?.First.Second // Uncaught TypeError: Cannot read property 'Second' of undefined
?.
浏览器支持 - 82%,截至2020年10月
Node 支持 - 版本 14+
是的,有一个。
在ES2020中,增加了可选链和可选函数调用。
const person = {
name: "Someone",
age: 28
}
console.log(person?.name) // "Someone"
console.log(person?.["age"]) // 28
person?.getAge?.() // no errors, just undefined
function optionalChaining(obj, chain) {
return chain
.split('.')
.reduce(function(acc, val) {
return acc ? acc[val] : undefined;
}, obj);
}
var user = {
address: {
street: 'No.969 West WenYi Road',
},
a: { b: { c: 2 } },
}
optionalChaining(user, 'address.street'); // 'No.969 West WenYi Road'
optionalChaining(user, 'a.b.c') // 2
仅补充上面的答案,现在您可以直接从NPM安装此Babel插件:
https://www.npmjs.com/package/babel-plugin-transform-optional-chaining
obj?.prop // optional static property access
obj?.[expr] // optional dynamic property access
func?.(...args) // optional function or method call
注:
为了允许 foo?.3:0 被解析为 foo ? .3 : 0(以满足向后兼容性要求),在词法语法的层面上添加了一个简单的前瞻,以便在该情况下不将字符序列 ?. 解释为单个标记(?. 标记不能紧接着小数位数字)。
https://github.com/tc39/proposal-optional-chaining
还值得一看: