Blog icon indicating copy to clipboard operation
Blog copied to clipboard

[MDN] Optional chaining

Open ChaoLiou opened this issue 4 years ago • 0 comments

Optional chaining

  • Optional chaining 運算子(?.) 是讀取物件底層的屬性值, 但不需要明確驗證每個 chaining 的參考都合法. 功能相似於 . chaining 運算子, 若參考是 nullish(nullundefined) 會造成錯誤, 而 ?. 會 short-circuits 運算回傳 undefined. 如果用於函式呼叫且不存在, 則回傳 undefined.

語法

obj.val?.prop
obj.val?.[expr]
obj.arr?.[index]
obj.func?.(args)

說明

  • 當參考或函式可能是 undefinednull 時, 簡化存取數值.
let nestedProp = obj.first && obj.first.second;
  • 存取 obj.first.second 前, 會確認 obj.first 不是 null(且不是 undefined).
let nestedProp = obj.first?.second;
// 相當於
let temp = obj.first;
let nestedProp = temp === null || temp === undefined ? undefined : temp.second;

用於函式呼叫

let result = someInterface.customMethod?.();

注意: 如果屬性不是函式, 使用 ?. 仍然有 TypeError 的例外(someInterface 的 customMethod 不是函式).

注意: 若 someInterface 本身是 nullundefined, 仍然有 TypeError(someInterface 是 null). 如果預期 someInterface 可能是 nullundefined, 必須也使用 ?.:

someInterface?.customMethod?.()

用於 callback 或事件處理

// ES2019 的寫法
function doSomething(onContent, onError) {
  try {
    // ... 做一些跟資料有關的事情
  } catch (err) {
    if (onError) {
      // 測試 onError 是否真的存在
      onError(err.message);
    }
  }
}
// 與函式呼叫使用可選串聯
function doSomething(onContent, onError) {
  try {
    // ... 做一些跟資料有關的事情
  } catch (err) {
    onError?.(err.message); // 如果 onError 是 undefined, 不會有例外
  }
}

用於運算式

  • 還可以用運算式存取屬性.
let nestedProp = obj?.["prop" + "Name"];

不可用於 = 的左側

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

用於存取陣列項目

let arrayItem = arr?.[42];

範例

基本範例

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

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

Short Circuits 求值

  • 若左側運算元是 nullundefined, 則運算式不會求值. 舉例:
let potentiallyNullObj = null;
let x = 0;
let prop = potentiallyNullObj?.[x++];

console.log(x); // 0 因為 x 沒有累加

用於巢狀結構

let customer = {
  name: "Carl",
  details: {
    age: 82,
    location: "Paradise Falls", // 未知的詳細地址
  },
};
let customerCity = customer.details?.address?.city;

let customerName = customer.name?.getName?.(); // 方法不存在

組合使用

  • 當找不到時, 要給預設值.
let customer = {
  name: "Carl",
  details: { age: 82 },
};
const customerCity = customer?.city ?? "未知城市";
console.log(customerCity); // 未知城市

瀏覽器相容

  • 除了 IE, 手持的 Opera Android 和 Samsung Internet 以外都支援.

ChaoLiou avatar Jan 27 '21 08:01 ChaoLiou