描述
可选链运算符(optional chaining operator)即?.运算符。它可以获取对象的属性或调用方法,如果对象是 undefined 或 null,那么会返回 undefined,而不是直接抛错。
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah',
},
};
const dogName = adventurer.dog?.name;
console.log(dogName);
// expected output: undefined
console.log(adventurer.someNonExistentMethod?.());
// expected output: undefined语法
obj.val?.prop
obj.val?.[expr]
obj.func?.(args)注意这里方法和属性变量的使用。
简单来说:?.运算符很像.运算符,除了它不会报错。如果 ?.运算符前面的内容是 undefined 或 null,那么后面接的属性的获取或方法的调用,不会抛错,并且返回 undefined。
场景
获取属性
在之前,如果你想要探索对象是否存在属性,要这样:
const nestedProp = obj.first && obj.first.second;这在 JS 中是惯用模式,但他有一下问题:
- 当嵌套层级很深时,代码冗余,过于啰嗦。
- 当
obj.first的值是 Falsy 的时候,比如0,那么nestedProp的值就会变成0,而不是期望的obj.first.second的值或者undefined
但如果你使用?.运算符,那就很奈斯:
const nestedProp = obj.first?.second;这样就解决了以上两个问题。
当然,你可能见过另一种解决方案,就是 lodash 的 get 方法
js_.get(obj, 'first.second', undefined);说实话,我更喜欢这个,因为它更强大,可惜的是,这并不是语言标准 😭
更准确来说,?.运算符其实是下面的语法糖:
const temp = obj.first;
const nestedProp =
temp === null || temp === undefined ? undefined : temp.second;?.运算符不可以用在没有声明的根对象上(如果用了会报错),但是可以用在已经声明的根对象的没有定义的属性上。

b?.a;
// Uncaught ReferenceError: b is not defined
let c = {};
c.d?.e;
// undefinedb 是未定义的对象,会报错,c 是定义了的,不会报错。
执行方法
const result = someInterface.customMethod?.();常见于一些 api 可能未实现的情况。这里的调用会返回 undefined,而不是报错。
注意:如果customMethod是已经存在的属性,但不是方法,那即使这样写了也是会报错的。
用于表达式
const nestedProp = obj?.['prop' + 'Name'];常用于数组:
function printMagicIndex(arr) {
console.log(arr?.[42]);
}
printMagicIndex([0, 1, 2, 3, 4, 5]); // undefined
printMagicIndex(); // undefined; if not using ?., this would throw?.运算符是不能在赋值左侧使用的,但.运算符是可以的
const object = {};
object?.property = 1; // SyntaxError: Invalid left-hand side in assignmen短路操作
const potentiallyNullObj = null;
let x = 0;
const prop = potentiallyNullObj?.[x++];
console.log(x); // 0 as x was not incremented如果?.前面的内容是 nullish,那么就不会执行后面的表达式,后续的属性访问也同样不会执行
const potentiallyNullObj = null;
const prop = potentiallyNullObj?.a.b;
// This does not throw, because evaluation has already stopped at
// the first optional chain其实就是下面的代码:
const potentiallyNullObj = null;
const prop =
potentiallyNullObj === null || potentiallyNullObj === undefined
? undefined
: potentiallyNullObj.a.b;但你如果用括号提升优先级,那么是有可能报错的:
const potentiallyNullObj = null;
const prop = (potentiallyNullObj?.a).b;示例
用于可选的回调函数
// Code written without optional chaining
function doSomething(onContent, onError) {
try {
// Do something with the data
} catch (err) {
// Testing if onError really exists
if (onError) {
onError(err.message);
}
}
}因为这里 onError 可能没有传值,所以要判断下,但如果用可选链,就比较简单:
// Using optional chaining with function calls
function doSomething(onContent, onError) {
try {
// Do something with the data
} catch (err) {
onError?.(err.message); // No exception if onError is undefined
}
}连续可选链
const customerCity = customer.details?.address?.city;与空值合并运算符结合使用
function printCustomerCity(customer) {
const customerCity = customer?.city ?? 'Unknown city';
console.log(customerCity);
}
printCustomerCity({
name: 'Nathan',
city: 'Paris',
}); // "Paris"
printCustomerCity({
name: 'Carl',
details: { age: 82 },
}); // "Unknown city"空值合并运算符
空值合并运算符 即??,它的作用是如果??左边是 nullish,那么返回右边,否则返回左边,它和||运算符很相似,||运算符左边是 Falsy 的话返回右边,否则返回左边。
参考: