Movatterモバイル変換


[0]ホーム

URL:


  1. 面向开发者的 Web 技术
  2. JavaScript
  3. JavaScript 参考
  4. 表达式和运算符
  5. 可选链运算符(?.)

此页面由社区从英文翻译而来。了解更多并加入 MDN Web Docs 社区。

View in EnglishAlways switch to English

可选链运算符(?.)

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since ⁨2020年7月⁩.

可选链运算符(?. 用于访问对象的属性或调用函数。如果使用此运算符访问的对象或调用的函数是undefinednull,则表达式会短路并计算为undefined,而不是抛出错误。

尝试一下

const adventurer = {  name: "Alice",  cat: {    name: "Dinah",  },};const dogName = adventurer.dog?.name;console.log(dogName);// Expected output: undefinedconsole.log(adventurer.someNonExistentMethod?.());// Expected output: undefined

语法

js
obj.val?.propobj.val?.[expr]obj.func?.(args)

描述

?. 运算符与. 链式运算符相似,不同之处在于,如果引用是空值nullundefined),它不会导致错误,而是使表达式短路并返回undefined。当用于函数调用时,如果给定函数不存在,它也会返回undefined

当访问链式属性时,如果存在引用可能缺失的情况,这将使表达式更简洁、更简短。在探索对象内容且无法确定哪些属性是必需的时,它也会很有帮助。

例如,考虑一个具有嵌套结构的对象obj。如果没有可选链,查找深层嵌套的子属性需要验证中间的引用,例如:

js
const nestedProp = obj.first && obj.first.second;

在访问obj.first.second 之前,要保证obj.first 的值不是null(也不是undefined)。这样做可以避免在不对obj.first 进行校验情况下直接访问obj.first.second 而可能引发的错误。

这是 JavaScript 中的一个惯用模式,但当链很长时,它会变得冗长,且不安全。例如,如果obj.first 是一个非nullundefined假值,比如0,它仍然会短路并使nestedProp 变为0,这可能是不可取的。

然而,使用可选链运算符(?.),在访问obj.first.second 之前,不再需要基于obj.first 的状态进行明确的测试和短路操作了:

js
const nestedProp = obj.first?.second;

通过使用?. 运算符取代. 运算符,JavaScript 会在尝试访问obj.first.second 之前,先隐式地检查并确定obj.first 既不是null 也不是undefined。如果obj.firstnull 或者undefined,表达式将会自动短路,并返回undefined

这等价于以下表达式,但实际上没有创建临时变量:

js
const temp = obj.first;const nestedProp =  temp === null || temp === undefined ? undefined : temp.second;

可选链运算符不能用于未声明的根对象,但可以用于值为undefined 的根对象。

js
undeclaredVar?.prop; // ReferenceError: undeclaredVar is not defined

函数调用中的可选链

当尝试调用一个可能不存在的方法时也可以使用可选链。例如,当使用某个 API 时,如果由于实现版本过旧或用户设备不具备某项功能而导致某个方法不可用时,可选链就很有用。

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

js
const result = someInterface.customMethod?.();

然而,如果存在一个具有这样名称的属性且不是函数,使用?. 仍然会引发一个TypeError 异常,即“someInterface.customMethod is not a function(不是一个函数)”。

备注:如果someInterface 自身是null 或者undefinedTypeError 异常仍会被抛出(someInterface is null)。如果你希望允许someInterface 自身也为null 或者undefined,你需要在这个位置使用?.someInterface?.customMethod?.()

eval?.() 是进入间接求值模式的最短方式。

表达式中的可选链

你也可以将可选链运算符与方括号表示法结合使用,它允许将表达式作为属性名传递:

js
const nestedProp = obj?.["prop" + "Name"];

这对于数组尤其有用,因为数组索引必须使用方括号来使用。

js
function printMagicIndex(arr) {  console.log(arr?.[42]);}printMagicIndex([0, 1, 2, 3, 4, 5]); // undefinedprintMagicIndex(); // undefined;如果未使用 ?. 运算符,这将抛出一个错误:“Cannot read properties of undefined (reading '42')”

无效的可选链

尝试为可选链表达式的结果赋值是无效的:

js
const object = {};object?.property = 1; // SyntaxError: Invalid left-hand side in assignment

模板字符串标签不能是可选链(参见SyntaxError: tagged template cannot be used with optional chain):

js
String?.raw`Hello, world!`;String.raw?.`Hello, world!`; // SyntaxError: Invalid tagged template on optional chain

new 表达式的构造函数不能是可选链(参见SyntaxError: new keyword cannot be used with an optional chain):

js
new Intl?.DateTimeFormat(); // SyntaxError: Invalid optional chain from new expressionnew Map?.();

短路

在使用可选链时,如果左操作数是nullundefined,则表达式将不会被求值。例如:

js
const potentiallyNullObj = null;let x = 0;const prop = potentiallyNullObj?.[x++];console.log(x); // x 未被递增,因此为 0

后续的属性访问也不会被求值。

js
const potentiallyNullObj = null;const prop = potentiallyNullObj?.a.b;// 这不会抛出错误,因为求值已经在第一个可选链处停止了

这等价于:

js
const potentiallyNullObj = null;const prop =  potentiallyNullObj === null || potentiallyNullObj === undefined    ? undefined    : potentiallyNullObj.a.b;

然而,这种短路行为只会在一个连续的属性访问“链”中发生。如果你将链中的某一部分进行分组,那么后续的属性访问仍然会被求值。

js
const potentiallyNullObj = null;const prop = (potentiallyNullObj?.a).b;// TypeError: Cannot read properties of undefined (reading 'b')

这等价于:

js
const potentiallyNullObj = null;const temp = potentiallyNullObj?.a;const prop = temp.b;

除了没有创建temp 变量。

示例

基本示例

此示例在一个不含bar 成员的 Map 中查找bar 成员的name 属性,因此结果是undefined

js
const myMap = new Map();myMap.set("foo", { name: "baz", desc: "inga" });const nameBar = myMap.get("bar")?.name;

处理可选的回调函数或事件处理器

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

js
// 不使用可选链的写法function doSomething(onContent, onError) {  try {    // 用数据做些事情  } catch (err) {    // 校验 onError 是否真的存在    if (onError) {      onError(err.message);    }  }}
js
// 使用可选链进行函数调用function doSomething(onContent, onError) {  try {    // 用数据做些事情  } catch (err) {    onError?.(err.message); // 如果 onError 是 undefined 也不会有异常  }}

连用可选链运算符

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

js
const customer = {  name: "Carl",  details: {    age: 82,    location: "Paradise Falls", // details 的 address 属性未有定义  },};const customerCity = customer.details?.address?.city;// 可选链也可以和函数调用一起使用const customerName = customer.name?.getName?.(); // 方法不存在,customerName 未定义

使用空值合并运算符

当未找到任何值时,可以在可选链之后使用空值合并运算符来构建一个默认值:

js
function printCustomerCity(customer) {  const customerCity = customer?.city ?? "未知城市";  console.log(customerCity);}printCustomerCity({  name: "Nathan",  city: "Paris",}); // "Paris"printCustomerCity({  name: "Carl",  details: { age: 82 },}); // "未知城市"

规范

Specification
ECMAScript® 2026 Language Specification
# prod-OptionalExpression

浏览器兼容性

参见

Help improve MDN

Learn how to contribute

This page was last modified on byMDN contributors.


[8]ページ先頭

©2009-2025 Movatter.jp