---
title: 可选链操作符
slug: Web/JavaScript/Reference/Operators/Optional_chaining
tags:
  - '?.'
  - JavaScript
  - Optional chaining (?.)
  - Reference
  - 参考
  - 可选链
  - 语言特性
  - 运算符
  - 链式调用
translation_of: Web/JavaScript/Reference/Operators/Optional_chaining
original_slug: Web/JavaScript/Reference/Operators/可选链
---
<div>{{JSSidebar("Operators")}}</div>

<p><strong>可选链</strong>操作符( <strong><code>?.</code></strong> )允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。<code>?.</code> 操作符的功能类似于 <code>.</code> 链式操作符,不同之处在于,在引用为空(<a href="https://wiki.developer.mozilla.org/en-US/docs/Glossary/nullish">nullish</a> ) ({{JSxRef("null")}} 或者 {{JSxRef("undefined")}}) 的情况下不会引起错误,该表达式短路返回值是 <code>undefined</code>。与函数调用一起使用时,如果给定的函数不存在,则返回 <code>undefined</code>。</p>

<p>当尝试访问可能不存在的对象属性时,可选链操作符将会使表达式更短、更简明。在探索一个对象的内容时,如果不能确定哪些属性必定存在,可选链操作符也是很有帮助的。</p>

<div>{{EmbedInteractiveExample("pages/js/expressions-optionalchainingoperator.html", "taller")}}</div>



<h2 id="语法">语法</h2>

<pre class="syntaxbox notranslate"><var>obj</var>?.<var>prop</var>
<var>obj</var>?.[<var>expr</var>]
<var>arr</var>?.[<var>index</var>]
<var>func</var>?.(<var>args</var>)
</pre>

<h2 id="描述">描述</h2>

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

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

<pre class="brush: js notranslate">let nestedProp = obj.first &amp;&amp; obj.first.second;</pre>

<p>为了避免报错,在访问<code>obj.first.second</code>之前,要保证 <code>obj.first</code> 的值既不是 <code>null</code>,也不是 <code>undefined</code>。如果只是直接访问 <code>obj.first.second</code>,而不对 <code>obj.first</code> 进行校验,则有可能抛出错误。</p>

<p>有了可选链操作符(<code>?.</code>),在访问 <code>obj.first.second</code> 之前,不再需要明确地校验 <code>obj.first</code> 的状态,再并用短路计算获取最终结果:</p>

<pre class="brush: js notranslate">let nestedProp = obj.first?.second;</pre>

<p>通过使用 <code>?.</code> 操作符取代 <code>.</code> 操作符,JavaScript 会在尝试访问 <code>obj.first.second</code> 之前,先隐式地检查并确定 <code>obj.first</code> 既不是 <code>null</code> 也不是 <code>undefined</code>。如果<code>obj.first </code>是 <code>null</code> 或者 <code>undefined</code>,表达式将会短路计算直接返回 <code>undefined</code>。</p>

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

<pre class="brush: js notranslate">let temp = obj.first;
let nestedProp = ((temp === null || temp === undefined) ? undefined : temp.second);</pre>

<h3 id="可选链与函数调用">可选链与函数调用</h3>

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

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

<pre class="brush: js notranslate">let result = someInterface.customMethod?.();</pre>

<div class="blockIndicator note">
<p><strong>注意:</strong> 如果存在一个属性名且不是函数, 使用 <code>?.</code> 仍然会产生一个 {{JSxRef("TypeError")}} 异常 (<code>x.y</code><code> is not a function</code>).</p>
</div>

<div class="blockIndicator note">
<p><strong>注意:</strong> 如果 <code>someInterface</code> 自身是 <code>null</code> 或者 <code>undefined</code> ,异常 {{JSxRef("TypeError")}} 仍会被抛出 <code>someInterface is null</code> 如果你希望允许 <code>someInterface</code> 也为 <code>null</code> 或者 <code>undefined</code> ,那么你需要像这样写 <code>someInterface?.customMethod?.()</code></p>
</div>

<h4 id="处理可选的回调函数或者事件处理器">处理可选的回调函数或者事件处理器</h4>

<p>如果使用<a href="/zh-CN/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment">解构赋值</a>来解构的一个对象的回调函数或 fetch 方法,你可能得到不能当做函数直接调用的不存在的值,除非你已经校验了他们的存在性。使用<code>?.</code>的你可以忽略这些额外的校验:</p>

<pre class="brush: js notranslate">//  ES2019的写法
function doSomething(onContent, onError) {
  try {
    // ... do something with the data
  }
  catch (err) {
    if (onError) { // 校验onError是否真的存在
      onError(err.message);
    }
  }
}
</pre>

<pre class="brush: js notranslate">// 使用可选链进行函数调用
function doSomething(onContent, onError) {
  try {
   // ... do something with the data
  }
  catch (err) {
    onError?.(err.message); // 如果onError是undefined也不会有异常
  }
}
</pre>

<h3 id="可选链和表达式">可选链和表达式</h3>

<p>当使用<a href="/zh-CN/docs/Web/JavaScript/Reference/Operators/Property_Accessors#方括号表示法">方括号与属性名</a>的形式来访问属性时,你也可以使用可选链操作符:</p>

<pre class="brush: js notranslate">let nestedProp = obj?.['prop' + 'Name'];</pre>

<h3 id="可选链不能用于赋值">可选链不能用于赋值</h3>

<pre class="notranslate"><code>let object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment</code></pre>

<h3 id="可选链访问数组元素">可选链访问数组元素</h3>

<pre class="notranslate">let arrayItem = arr?.[42];</pre>

<h2 id="例子">例子</h2>

<h3 id="基本例子">基本例子</h3>

<p>如下的例子在一个不含 <code>bar</code> 成员的 Map 中查找 <code>bar</code> 成员的 <code>name</code> 属性,因此结果是 <code>undefined</code>。</p>

<pre class="brush: js notranslate">let myMap = new Map();
myMap.set("foo", {name: "baz", desc: "inga"});

let nameBar = myMap.get("bar")?.name;</pre>

<h3 id="短路计算">短路计算</h3>

<p>当在表达式中使用可选链时,如果左操作数是 <code>null</code> 或 <code>undefined</code>,表达式将不会被计算,例如:</p>

<pre class="brush: js notranslate">let potentiallyNullObj = null;
let x = 0;
let prop = potentiallyNullObj?.[x++];

console.log(x); // x 将不会被递增,依旧输出 0
</pre>

<h3 id="连用可选链操作符">连用可选链操作符</h3>

<p>可以连续使用可选链读取多层嵌套结构:</p>

<pre class="brush: js notranslate">let customer = {
  name: "Carl",
  details: {
    age: 82,
    location: "Paradise Falls" // details 的 address 属性未有定义
  }
};
let customerCity = customer.details?.address?.city;

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

<h3 id="使用空值合并操作符">使用空值合并操作符</h3>

<p>{{JSxRef("Operators/Nullish_Coalescing_Operator", "空值合并操作符")}}可以在使用可选链时设置一个默认值:</p>

<pre class="brush: js notranslate"><code>let customer = {
  name: "Carl",
  details: { age: 82 }
};
let customerCity = customer?.city ?? "暗之城";
console.log(customerCity); // “暗之城”</code></pre>

<h2 id="规范">规范</h2>

<table class="standard-table">
 <thead>
  <tr>
   <th scope="col">规范</th>
   <th scope="col">状态</th>
   <th scope="col">备注</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>{{SpecName('ESDraft', '#prod-OptionalExpression', 'optional expression')}}</td>
   <td>Stage 4</td>
   <td></td>
  </tr>
 </tbody>
</table>

<h2 id="浏览器兼容性">浏览器兼容性</h2>

<div>


<p>{{Compat("javascript.operators.optional_chaining")}}</p>

<h3 id="Implementation_Progress">Implementation Progress</h3>

<p>The following table provides a daily implementation status for this feature because this feature has not yet reached cross-browser stability. The data is generated by running the relevant feature tests in <a href="https://github.com/tc39/test262">Test262</a>, the standard test suite of JavaScript, in the nightly build, or the latest release of each browser's JavaScript engine.</p>

<p>{{EmbedTest262ReportResultsTable("optional-chaining")}}</p>
</div>

<h2 id="参见">参见</h2>

<ul>
 <li>{{JSxRef("Operators/Nullish_Coalescing_Operator", "空值合并操作符")}}</li>
 <li><a href="https://github.com/tc39/proposals">TC39 提案</a></li>
</ul>