diff options
Diffstat (limited to 'files/zh-cn/web/javascript/reference/operators/optional_chaining/index.html')
-rw-r--r-- | files/zh-cn/web/javascript/reference/operators/optional_chaining/index.html | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/files/zh-cn/web/javascript/reference/operators/optional_chaining/index.html b/files/zh-cn/web/javascript/reference/operators/optional_chaining/index.html new file mode 100644 index 0000000000..6b45bc4aad --- /dev/null +++ b/files/zh-cn/web/javascript/reference/operators/optional_chaining/index.html @@ -0,0 +1,203 @@ +--- +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 && 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> |