JavaScript 可選鏈(optional chaining)

可選鏈

可選鏈(Optional chaining) ?. 是一種以安全的方式去訪問嵌套的對象屬性,即使某個屬性根本就不存在。
這是一項新的提案,老舊瀏覽器可能需要 polyfills。

一、解決的問題:

1、問題一

如果用戶信息中,地址是非必填的,那我們就無法安全地訪問地址的某一個屬性:

let user = {}; // 用戶可能沒有填地址

alert(user.address.street); // 報錯

2、問題二

獲取一個 DOM 元素,但這個 DOM 元素可能不存在:

// 當 querySelector(...) 的結果爲 null 的時候,程序會報錯
let html = document.querySelector('.my-element').innerHTML;

在可選鏈出現前,我們一般通過邏輯與操作來解決:

let user = {}; // 沒有地址的用戶

alert(user && user.address && user.address.street); // undefined (不會報錯)

使用邏輯與操作符可以確保表達式的所有部分都能夠正確執行,但寫法卻比較笨重。

二、基礎用法

可選鏈 ?. 能夠使代碼變得簡便,當位於 ?. 前面的值爲 undefinednull 時,會立即阻止代碼的執行,並返回 undefined。

通過可選鏈,我們可以安全地訪問用戶的地址:

let user = {}; // 一個沒有地址的用戶

alert(user?.address?.street); // undefined (不會報錯)

即使 user 對象不存在,使用可選鏈訪問它的地址屬性也不會報錯:

let user = null;

alert(user?.address); // undefined
alert(user?.address.street); // undefined

注意

  • 不要過度使用可選鏈,一般只在希望某個值可能不存在的情況下,才使用 ?.例如,根據我們的代碼邏輯,user 對象必須存在,但 address 屬性是可選的,所以 user.address?.street 纔是更好的選擇。這樣,由於其他原因導致的 user 對象爲 undefined 的情況才能被快速發現。
  • 位於 ?. 前的變量必須被顯示聲明,如果 user 這個變量根本沒有被聲明,那麼 user?.anything 將會觸發一個錯誤:
// ReferenceError: user is not defined
user?.address;

此處必須有變量聲明語句 let/const/var, 可選鏈對未聲明的變量無效

三、其它用法

1、短路

上面說到,在可選鏈中 ?. 前面的部分值爲 null 或 undefined 時,會立即停止執行。
所以,如果在其後面如果有函數的調用,或者其他操作,都不會執行。

let user = null;
let x = 0;
user?.sayHi(x++); // 什麼都不會做
alert(x);   // 0,值沒有自增

2、?.()

?.() 可用於執行一個可能不存在的函數。
下面的代碼中,有些用戶擁有 admin 方法,有些用戶沒有:

let user1 = {
  admin() {
    alert("I am admin");
  }
};

let user2 = {};

user1.admin?.(); // I am admin
user2.admin?.(); // 啥都沒有(因爲沒有這樣的方法)

這裏首先使用點符號(userAdmin.admin)來獲取 admin 方法,因爲 user 對象一定存在,所以可以安全地讀取。

然後 ?.() 會檢查它左邊的部分:如果 admin 函數存在,那麼就調用運行它(user1)。否則運算停止且不報錯(user2)。

3、?.[]

?. 語法同樣可以在需要用中括號去訪問屬性時使用,使用它可以安全的訪問一個或許還不存在的對象的屬性:

let user1 = {
  firstName: "John"
};

let user2 = null; // 假設,我們不能授權此用戶

let key = "firstName";

alert(user1?.[key]); // John
alert(user2?.[key]); // undefined

alert(user1?.[key]?.something?.not?.existing); // undefined

?. 可以與 delete 操作符共用

delete user?.name; // 如果 user 存在,則刪除 user.name

需要注意的是,使用 ?. 可以進行刪除和讀取操作,但是不能進行賦值操作

let user = null;

user?.name = "John"; // Error,不起作用
// 因爲它在計算的是 undefined = "John"

四、總結

可選鏈 ?. 有三種形式:

  • obj?.prop —— 如果 obj 存在則返回 obj.prop,否則返回 undefined
  • obj?.[prop] —— 如果 obj 存在則返回 obj[prop],否則返回 undefined
  • obj.method?.() —— 如果 obj.method 存在則調用 obj.method(),否則返回 undefined

這幾種形式都是檢查 ?. 左側的值是否爲 null 或 undefine,如果不是的話則繼續執行。

注意:應該僅在 ?. 左側的值可能不存在的情況下才使用,這樣發生錯誤時才能更容易地找到問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章