可选链

可选链操作符?.允许读取一个被连接对象的深层次的属性的值而无需明确校验链条上每一个引用的有效性。?.运算符功能类似于.运算符,不同之处在于如果链条上的一个引用是nullundefined.操作符会引起一个错误,?.操作符取而代之的是会按照短路计算的方式返回一个undefined。当?.操作符用于函数调用时,如果该函数不存在也将会返回undefined。
当访问链条上可能存在的属性却不存在时,?.操作符将会使表达式更短和更简单。当不能保证哪些属性是必需的时,?.操作符对于探索一个对象的内容是很有帮助的。
警告:截至2019年8月,没有本地环境实现了这个功能。如果你使用Babel,你可以使用 this plugin 来模拟可选链。

{{EmbedInteractiveExample("pages/js/expressions-optionalchainingoperator.html")}}

语法

obj?.prop
obj?.[expr]
func?.(args)

描述

通过连接的对象的引用或函数可能是undefinednull时,可选链操作符提供了一种方法来简化被连接对象的值访问。

比如,思考一个存在嵌套结构的对象obj。不使用可选链的话,查找一个深度嵌套的子属性需要验证之间的引用,例如:

let nestedProp = obj.first && obj.first.second;

在访问obj.first.second之前,obj.first 的值要被确认非null(且不是undefined)。目的是为了防止错误发生,如果简单直接的访问obj.first.second而不对obj.first 进行校验有可能产生错误。

有了可选链操作符 (?.),在访问obj.first.second:之前,你将不需要明确的校验和短路计算obj.first的状态:

let nestedProp = obj.first?.second;

通过使用?.操作符取代.操作符。JavaScript知道在尝试访问obj.first.second之前先明确的校验并确定obj.firstt是非null且非undefined。如果obj.firstnullundefined,表达式将会短路计算直接返回undefined

这等价于以下表达式:

let nestedProp = (obj.first == null ? undefined : obj.first.second);

可选链与函数调用

当尝试调用一个可能不存在的方法时也可以使用可选链。这将是很有帮助的,比如,当使用一个API的方法可能不可用时,要么因为实现的版本问题要么因为当前用户的设备不支持该功能。

函数调用时如果被调用的方法不存在,使用可选链可以使表达式自动返回undefined而不是抛出一个异常。

let result = someInterface.customMethod?.();

注意: 如果存在一个属性名且不是函数, 使用 ?. 仍然会产生一个 TypeError异常 (x.y is not a function).

处理可选的callbacks或事件handlers

如果你使用a destructuring assignment来解构的一个对象的callbacks或fetch方法,你可能得到不能当做函数直接调用的不存在的值,除非你已经校验了他们的存在性。使用?.的你可以忽略这些额外的校验:

//  ES2019的写法
function doSomething(onContent, onError) {
  try {
    // ... do something with the data 
  }
  catch (err) {
    if (onError) { // 校验onError是否真的存在
      onError(err.message);
    }
  }
}
// 使用可选链进行函数调用
function doSomething(onContent, onError) {
  try {
   // ... do something with the data
  }
  catch (err) {
    onError?.(err.message); // 如果onError是undefined也不会有异常
  }
}

可选链和表达式

当使用表达式the bracket notation of the property accessor访问属性时,你也可以使用可选链操作符:

let nestedProp = obj?.['prop' + 'Name'];

例子

基本例子

如下的例子在一个不存在bar成员的map中查找barname的值,因此结果是undefined

let myMap = new Map();
myMap.set("foo", {name: "baz", desc: "inga"});

let nameBar = myMap.get("bar")?.name;

短路计算

当在表达式中使用可选链时,如果左操作数是nullundefined,表达式将不会被计算,例如:

let potentiallyNullObj = null;
let x = 0;
let prop = potentiallyNullObj?.[x++];

console.log(x); // 作为0的x将不会被递增,依旧输出0

叠加可选链操作符

嵌套结构,可以多次使用可选链:

let customer = {
  name: "Carl",
  details: {
    age: 82,
    location: "Paradise Falls" // detailed的address属性是未知的
  }
};
let customerCity = customer.details?.address?.city;

// … 可选链也可以和函数调用一起使用
let duration = vacations.trip?.getTime?.();

说明

说明 状态 建议
Proposal for the "optional chaining" operator Stage 3

Browser compatibility

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
Optional chaining operator (?.)
Experimental
Chrome No support NoEdge No support NoFirefox No support NoIE No support NoOpera No support NoSafari ? WebView Android No support NoChrome Android No support NoFirefox Android No support NoOpera Android No support NoSafari iOS ? Samsung Internet Android No support Nonodejs No support No

Legend

No support  
No support
Compatibility unknown  
Compatibility unknown
Experimental. Expect behavior to change in the future.
Experimental. Expect behavior to change in the future.

See also