「譯」JS新特性「可選鏈式調用」

在JavaScript中長的鏈式調用可能容易出錯,由於任何一步均可能出現nullundefined(也被稱爲「無效」值)。檢查每一個步驟的屬性是否存在很容易變成深層次嵌套的if聲明或者複製屬性訪問鏈的長的if條件:javascript

// 容易出錯的版本,可能拋出錯誤
const nameLength = db.user.name.length;

// 不容易出錯,可是難以閱讀
let nameLength;
if (db && db.user && db.user.name)
  nameLength = db.user.name.length;
複製代碼

以上還能夠使用三元表達式,可是一樣難以閱讀:java

const nameLength =
  (db
    ? (db.user
      ? (db.user.name
        ? db.user.name.length
        : undefined)
      : undefined)
    : undefined);
複製代碼

介紹可選調用鏈

咱們並不想寫出這樣的代碼,因此有一些代替方案是可取的。一些語言(例如swift,具體查看https://www.jianshu.com/p/5599b422afb0)針對這個問題提供了優雅的解決方案——可選調用鏈。 根據最近的規範,「可選調用鏈是一個或多個屬性訪問和函數調用的鏈,以?.開頭」。git

使用新的可選調用鏈,咱們能夠重寫上面的demo:github

// 依然檢查錯誤,可是可讀性更高
const nameLength = db?.user?.name?.length;
複製代碼

使用可選調用鏈,當dbuser,或nameundefined或者null的時候,nameLength被初始化爲undefined,而不是像以前那樣拋出錯誤。數據庫

**Note:**可選調用鏈比咱們本身用if(db && db.user && db.user.name)檢查更加健壯,例如,若是name是一個空字符串,可選字符串會將name?.length改成name.length而後獲得正確的長度0,可是若是像咱們以前那樣作判斷,不會獲得正確的值,由於在if語句中空字符和false的行爲相同。可選調用鏈修復了這個常見的bug。swift

其餘的語法形式:調用和動態屬性

還有一個用於調用可選方法的運算符:數組

// 使用可選方法擴展接口,僅適用於管理員用戶
const adminOption = db?.user?.validateAdminAndGetPrefs?.().option;
複製代碼

這個語法可能有點兒出乎意料,由於這裏的運算符是?.(),該運算符適用於以前的表達式。安全

可選調用鏈還有第三種用法,便可選動態屬性訪問?.[]。若是對象中有該key對應的value,則返回value,不然返回undefined。demo以下:函數

// 使用動態屬性名訪問屬性對應的值
const optionName = 'optional setting';
const optionLength = db?.user?.preferences?.[optionName].length;
複製代碼

該用法一樣適用於可選索引數組,例如:ui

// 若是`userArray`是`null`或`undefined`,則`userName`被優雅的賦值爲`undefined`
const userIndex = 42;
const userName = usersArray?.[userIndex].name;
複製代碼

可選調用鏈能夠和nullish coalescing ?? 操做符結合使用,返回一個非undefined的默認值。這樣能夠使用指定的默認值安全的進行深層屬性訪問,解決了以前用戶須要JavaScript庫才能解決的問題,例如lodash的_.get

const object = { id: 123, names: { first: 'Alice', last: 'Smith' }};

{ // With lodash:
  const firstName = _.get(object, 'names.first');
  // → 'Alice'

  const middleName = _.get(object, 'names.middle', '(no middle name)');
  // → '(no middle name)'
}

{ // With optional chaining and nullish coalescing:
  const firstName = object?.names?.first ?? '(no first name)';
  // → 'Alice'

  const middleName = object?.names?.middle ?? '(no middle name)';
  // → '(no middle name)'
}
複製代碼

可選調用鏈的屬性

可選調用鏈有一些有趣的屬性:短路(short-circuiting)堆疊(stacking)可選刪除(optonal deletion)。下面經過例子來了解這些屬性。

*短路(short-circuiting)*即若是可選調用鏈提早返回則不計算表達式的其他部分:

// 只有在`db`和`user`不是`undefined`的狀況下`age`纔會+1
db?.user?.grow(++age);
複製代碼

*堆疊(stacking)*意味着能夠在一系列屬性訪問中應用多個可選調用運算符:

// 一個可選鏈能夠跟隨另外一個可選鏈
const firstNameLength = db.users?.[42]?.names.first.length;
複製代碼

可是,考慮在一個鏈中使用多個可選調用運算符。若是一個value保證是有效的,那麼不鼓勵使用?.去訪問屬性。像在以前的例子中,db必然是定義的,可是db.usersdb.users[42]多是未定義的。若是數據庫中有這樣的用戶,那麼name.first.length也是始終被定義的。

*可選刪除(optonal deletion)*就是delete操做符能夠和可選鏈一塊兒使用:

// 當且僅當`db`是定義過的時候刪除`db.user`
delete db?.user;
複製代碼

更多細節能夠訪問該提案的語義部分

原文連接:v8.dev/features/op…

相關文章
相關標籤/搜索