关于javascript:ES2020-系列可选链-为啥出现我们能用它来干啥

34次阅读

共计 3894 个字符,预计需要花费 10 分钟才能阅读完成。

可选链 “?.”

可选链 ?. 是一种拜访嵌套对象属性的平安的形式。即便两头的属性不存在,也不会呈现谬误。

“不存在的属性”的问题

如果你才刚开始读此教程并学习 JavaScript,那可能还没接触到这个问题,但它却相当常见。

举个例子,假如咱们有很多个 user 对象,其中存储了咱们的用户数据。

咱们大多数用户的地址都存储在 user.address 中,街道地址存储在 user.address.street 中,但有些用户没有提供这些信息。

在这种状况下,当咱们尝试获取 user.address.street,而该用户恰好没提供地址信息,咱们则会收到一个谬误:

let user = {}; // 一个没有 "address" 属性的 user 对象

alert(user.address.street); // Error!

这是预期的后果。JavaScript 的工作原理就是这样的。因为 user.addressundefined,尝试读取 user.address.street 会失败,并收到一个谬误。

然而在很多理论场景中,咱们更心愿失去的是 undefined(示意没有 street 属性)而不是一个谬误。

……还有另一个例子。在 Web 开发中,咱们能够应用非凡的办法调用(例如 document.querySelector('.elem'))以对象的模式获取一个网页元素,如果没有这种对象,则返回 null

// 如果 document.querySelector('.elem') 的后果为 null,则这里不存在这个元素
let html = document.querySelector('.elem').innerHTML; // 如果 document.querySelector('.elem') 的后果为 null,则会呈现谬误 

同样,如果该元素不存在,则拜访 null.innerHTML 时会出错。在某些状况下,当元素的缺失是没问题的时候,咱们心愿避免出现这种谬误,而是承受 html = null 作为后果。

咱们如何实现这一点呢?

可能最先想到的计划是在拜访该值的属性之前,应用 if 或条件运算符 ? 对该值进行查看,像这样:

let user = {};

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

这样能够,这里就不会呈现谬误了……然而不够优雅。就像你所看到的,"user.address" 在代码中呈现了两次。对于嵌套档次更深的属性就会呈现更屡次这样的反复,这就是问题了。

例如,让咱们尝试获取 user.address.street.name

咱们既须要查看 user.address,又须要查看 user.address.street

let user = {}; // user 没有 address 属性

alert(user.address ? user.address.street ? user.address.street.name : null : null);

这样就太扯淡了,并且这可能导致写进去的代码很难让他人了解。

甚至咱们能够先疏忽这个问题,因为咱们有一种更好的实现形式,就是应用 && 运算符:

let user = {}; // user 没有 address 属性

alert(user.address && user.address.street && user.address.street.name); // undefined(不报错)

顺次对整条门路上的属性应用与运算进行判断,以确保所有节点是存在的(如果不存在,则进行计算),但依然不够优雅。

就像你所看到的,在代码中咱们依然反复写了好几遍对象属性名。例如在下面的代码中,user.address 被反复写了三遍。

这就是为什么可选链 ?. 被退出到了 JavaScript 这门编程语言中。那就是彻底地解决以上所有问题!

可选链

如果可选链 ?. 后面的局部是 undefined 或者 null,它会进行运算并返回该局部。

为了扼要起见,在本文接下来的内容中,咱们会说如果一个属性既不是 null 也不是 undefined,那么它就“存在”。

换句话说,例如 value?.prop

  • 如果 value 存在,则后果与 value.prop 雷同,
  • 否则(当 valueundefined/null 时)则返回 undefined

上面这是一种应用 ?. 平安地拜访 user.address.street 的形式:

let user = {}; // user 没有 address 属性

alert(user?.address?.street); // undefined(不报错)

代码简洁明了,也不必反复写好几遍属性名。

即便 对象 user 不存在,应用 user?.address 来读取地址也没问题:

let user = null;

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

请留神:?. 语法使其后面的值成为可选值,但不会对其前面的起作用。

例如,在 user?.address.street.name 中,?. 容许 usernull/undefined,但仅此而已。更深层次的属性是通过惯例形式拜访的。如果咱们心愿它们中的一些也是可选的,那么咱们须要应用更多的 ?. 来替换 .

不要适度应用可选链:

咱们应该只将 ?. 应用在一些货色能够不存在的中央。

例如,如果依据咱们的代码逻辑,user 对象必须存在,但 address 是可选的,那么咱们应该这样写 user.address?.street,而不是这样 user?.address?.street

所以,如果 user 凑巧因为失误变为 undefined,咱们会看到一个编程谬误并修复它。否则,代码中的谬误在不失当的中央被打消了,这会导致调试更加艰难。

可选链 ?. 前的变量必须已申明

如果未声明变量 user,那么 user?.anything 会触发一个谬误:

// ReferenceError: user is not defined
user?.address;

?. 前的变量必须已申明(例如 let/const/var user 或作为一个函数参数)。可选链仅实用于已申明的变量。

短路效应

正如后面所说的,如果 ?. 右边局部不存在,就会立刻进行运算(“短路效应”)。

所以,如果前面有任何函数调用或者副作用,它们均不会执行。

例如:

let user = null;
let x = 0;

user?.sayHi(x++); // 没有 "sayHi",因而代码执行没有触达 x++

alert(x); // 0,值没有减少 

其它变体:?.(),?.[]

可选链 ?. 不是一个运算符,而是一个非凡的语法结构。它还能够与函数和方括号一起应用。

例如,将 ?.() 用于调用一个可能不存在的函数。

在上面这段代码中,有些用户具备 admin 办法,而有些没有:

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

let userGuest = {};

userAdmin.admin?.(); // I am admin

userGuest.admin?.(); // 啥都没有(没有这样的办法)

在这两行代码中,咱们首先应用点符号(user1.admin)来获取 admin 属性,因为用户对象肯定存在,因而能够平安地读取它。

而后 ?.() 会查看它右边的局部:如果 admin 函数存在,那么就调用运行它(对于 user1)。否则(对于 user2)运算进行,没有谬误。

如果咱们想应用方括号 [] 而不是点符号 . 来拜访属性,语法 ?.[] 也能够应用。跟后面的例子相似,它容许从一个可能不存在的对象上平安地读取属性。

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"

这还不是那么智能。

总结

可选链 ?. 语法有三种模式:

  1. obj?.prop —— 如果 obj 存在则返回 obj.prop,否则返回 undefined
  2. obj?.[prop] —— 如果 obj 存在则返回 obj[prop],否则返回 undefined
  3. obj.method?.() —— 如果 obj.method 存在则调用 obj.method(),否则返回 undefined

正如咱们所看到的,这些语法模式用起来都很简略间接。?. 查看右边局部是否为 null/undefined,如果不是则持续运算。

?. 链使咱们可能平安地拜访嵌套属性。

然而,咱们应该审慎地应用 ?.,仅在当右边局部不存在也没问题的状况下应用为宜。以保障在代码中有编程上的谬误呈现时,也不会对咱们暗藏。


古代 JavaScript 教程:开源的古代 JavaScript 从入门到进阶的优质教程。React 官网文档举荐,与 MDN 并列的 JavaScript 学习教程。

在线收费浏览:https://zh.javascript.info


微信扫描下方二维码,关注公众号「技术漫谈」,订阅更多精彩内容。

正文完
 0