可選鏈
可選鏈(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 (不會報錯)
使用邏輯與操作符可以確保表達式的所有部分都能夠正確執行,但寫法卻比較笨重。
二、基礎用法
可選鏈 ?.
能夠使代碼變得簡便,當位於 ?.
前面的值爲 undefined
或 null
時,會立即阻止代碼的執行,並返回 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,如果不是的話則繼續執行。
注意:應該僅在 ?.
左側的值可能不存在的情況下才使用,這樣發生錯誤時才能更容易地找到問題。