假设一个对象 user
,你需要拿到该对象的 address
属性里的 street
属性,但是该对象的 address
属性可能不存在,如果你使用 user.address.street
可能报错,因为对一个 null
使用 点操作是会报错的。这种情况是很常见的,例如一个用户的个人信息,里面的地址不是必填的,这时你去执行上面的操作是可能报错的。
常规的解决办法是使用 if
进行判断,或者使用三目运算符 ? :
let user = {};
alert(user.address ? user.address.street : undefined);
但是这样做不太优雅,因为 user.address
出现了两次。
对于嵌套层次更深的属性,代码会变得更丑,因为需要更多的重复。
例如,让我们以相同的方式尝试获取 user.address.street.name
。
let user = {};
alert(user.address ? user.address.street ? user.address.street.name : null : null);
这样代码的可读性差,而且很长。
另一种解决方式是用 &&
操作符,又称短路逻辑。
let user = {};
alert( user.address && user.address.street && user.address.street.name );
上面的方式都能解决问题,并且不会报错,但是都不够优雅,因为 user.address
出现了多次。
于是JavaScript 引入新特性:可选链 “?.”
可选链"?."
如果可选链 ?.
前面的值为 undefined
或者 null
,它会停止运算并返回 undefined
。
改用可选链之后的代码
let user = {}; // user 没有 address 属性
alert( user?.address?.street ); // undefined (不报错)
对于上面的代码,如果 user
不存在,则返回 undefined
后面的代码不再执行,如果存在则判断 address
属性存不存在,不存在返回 undefined
,存在则执行user.address
依次类推。
以上的方式不仅可以用在属性,也可以用在函数调用上
let userAdmin = {
admin() {
alert("I am admin");
}
};
let user = {};
userAdmin.admin?.(); // I am admin
user.admin?.(); // 啥也没发生(没有这样的方法)
还可以使用 ?.[]
let key = "firstName";
let user1 = {
firstName: "Jhon"
};
let user2 = null;
alert( user1?.[key] ); // Jhon
alert( user2?.[key] ); // undefined
总结
可选链 ?.
语法有三种形式:
obj?.prop
—— 如果obj
存在则返回obj.prop
,否则返回undefined
。obj?.[prop]
—— 如果obj
存在则返回obj[prop]
,否则返回undefined
。obj.method?.()
—— 如果obj.method
存在则调用obj.method()
,否则返回undefined
。