写点什么

了解 JavaScript 新特性:Optional Chaining

  • 2019-10-25
  • 本文字数:2083 字

    阅读完需:约 7 分钟

了解JavaScript新特性:Optional Chaining

Optional Chaining 是 JavaScript 的一个新特性,它允许我们在尝试访问对象的属性之前检查对象是否存在。其他语言也有类似的东西,例如,C# 的 Null Conditional 操作符,与 Optional Chaining 非常类似。


JavaScript 中的长属性访问链很容易出错,因为它们中的任何一个都可能评估为nullundefined(也称为“空”值)。要在每个步骤都中检查属性是否存在,很容易搞出来一个深层嵌套结构的if语句或一个长长的if条件复制属性访问链:


// Error prone-version, could throw.const nameLength = db.user.name.length;
// Less error-prone, but harder to read.let nameLength;if (db && db.user && db.user.name) nameLength = db.user.name.length;
复制代码


上面的代码也可以使用三元操作符表示,但并不能提高可读性。


const nameLength =  (db    ? (db.user      ? (db.user.name        ? db.user.name.length        : undefined)      : undefined)    : undefined);
复制代码

介绍 Optional Chaining 操作符

你当然不想编写这样的代码,因此希望有其他选择。其他一些语言使用了被称为“optional chaining”(可选链)的功能提供了一种优雅的解决方案。根据最近的规范提案,“Optinal Chain 是一个或多个属性访问和函数调用的链,其中第一个以令牌?.开头”。


使用新的 Optinal Chaining 操作符,我们可以重写上述示例,如下所示:


// Still checks for errors and is much more readable.const nameLength = db?.user?.name?.length;
复制代码


如果dbusernameundefinednull会发生什么?使用 Optinal Chaining 操作符时,JavaScript 会将nameLength初始化为undefined,而不是抛出错误。


请注意,此行为也比我们检查if (db && db.user && db.user.name)更加健壮。例如,如果name一直都是字符串怎么办?我们可以将name?.length更改为name.length。如果name是一个空字符串,我们仍将获得正确的0长度。这是因为空字符串是虚值:它在if子句中的行为类似false。Optinal Chaining 操作符可修复这类常见的错误。

其他语法形式:调用和动态属性

还有一个用来调用可选方法的操作符版本:


// Extends the interface with an optional method, which is present// only for admin users.const adminOption = db?.user?.validateAdminAndGetPrefs?.().option;
复制代码


这里的语法可能让人感到意外,因为?.()是实际的操作符,它适用于 之前 的表达式。


操作符还有第三种用法,就是可选的动态属性访问,通过?.[]实现。它要么返回括号中的参数所引用的值,或者如果没有可以获取值的对象,则返回undefined。按照上面的示例,下面是一个可能的用例:


// Extends the capabilities of the static property access// with a dynamically generated property name.const optionName = 'optional setting';const optionLength = db?.user?.preferences?.[optionName].length;
复制代码


最后一种形式也可用于可选的索引数组,例如:


// If the `usersArray` is `null` or `undefined`,// then `userName` gracefully evaluates to `undefined`.const userIndex = 42;const userName = usersArray?.[userIndex].name;
复制代码


需要非undefined默认值时,Optinal Chaining 操作符可以与双问号?? 操作符组合使用。这样可以使用指定的默认值进行安全的深层属性访问,从而解决了以前需要用户域库(例如 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)'}
复制代码

Optinal Chaining 操作符的属性

Optinal Chaining 操作符具有一些有趣的属性:短路、堆叠和可选删除。下面通过一个示例逐一介绍。


短路(Short-circuiting)意味着如果 Optinal Chaining 操作符提前返回,则不对表达式的其余部分求值:


// `age` is incremented only if `db` and `user` are defined.db?.user?.grow(++age);
复制代码


堆叠(Stacking)意味着可以对一系列属性访问应用多个 Optinal Chaining 操作符:


// An optional chain may be followed by another optional chain.const firstNameLength = db.users?.[42]?.names.first.length;
复制代码


尽管如此,在一条链中使用多个 Optinal Chaining 操作符前请三思。如果一个值保证不为空,则不建议使用?.访问它的属性。在上面的示例中,db被视为始终已定义,但是db.usersdb.users [42]可能未定义。如果数据库中有这样的用户,则假定始终定义names.first.length


可选删除(Optinal deletion)意味着可以将delete操作符与 Optinal Chain 结合使用:


// `db.user` is deleted only if `db` is defined.delete db?.user;
复制代码


更多信息参阅提案的语义部分


原文链接https://v8.dev/features/optional-chaining


2019-10-25 19:484312

评论

发布
暂无评论
发现更多内容

44 K8S之污点与容忍度

穿过生命散发芬芳

k8s 28天写作 12月日更

面向视频原生,火山引擎视频云与边缘云软硬一体的新云解决方案

火山引擎边缘云

基础设施 边缘计算 云服务 视频 云计算,

数据产品经理实战合集

第519区

内容合集 签约计划第二季 技术专题合集

我们的护城河在哪

hackstoic

商业模式

飞桨企业版重磅发布智能边缘控制台,5分钟零代码自动化模型部署

百度大脑

人工智能 百度

阿里云手机正式公测,定义手机全新接入方式

阿里云弹性计算

阿里云 弹性云手机

Spring Cloud Config

李子捌

微服务 28天写作 12月日更

盘点前端进阶之路的零到一

速冻鱼

前端 内容合集 签约计划第二季 12月日更

CODING x 百果园,水果零售龙头迈出 DevOps 体系建设第一步

CODING DevOps

DevOps CODING 百果园 合作

实用机器学习笔记十三:随机梯度下降

打工人!

机器学习 AI 算法 学习笔记 12月日更

音视频学习--视频特性测试

Fenngton

音视频 测试环境 签约计划第二季

在人均配备升降桌的公司工作,是一种怎样的体验?

LigaAI

开发者 LigaAI

Go+ JSON 编码和解码处理教程(5.4)

liuzhen007

28天写作 12月日更

Volatile 原理六:图解指令重排

悟空聊架构

volatile 28天写作 悟空聊架构 12月日更 指令重排

TCP 拥塞控制算法

程序员历小冰

TCP 网络 28天写作 12月日更

【AI最前线】精准优质-资讯|分享|热议第44期

百度大脑

人工智能

【C++20协程原理】从Linux线程、线程与异步编程、协程与异步,一文带你弄清楚

奔着腾讯去

线程 多线程 进程 协程 C++20

大势已来,区块链的真正价值是什么?

CECBC

区块链引发了一场独特的社会运动

CECBC

团队实行996,就有人离职,怎么办?

石云升

996 28天写作 加班文化 职场经验 12月日更

贝壳Flutter体系化建设实践

贝壳大前端技术团队

技术专题合集

读《思辨与立场》-03公允无偏

wood

28天写作 批判性思维 思辨与立场

读《刷新》有感

将军-技术演讲力教练

Redis(三):持久化

IT巅峰技术

Java redis 架构师 分布式缓存 redis分布式

性能分析之 PHP 应用进程过多导致的 page faults

zuozewei

php 性能测试 性能分析 签约计划第二季

不可错过的年度AI盛会 | 2021 新一代人工智能院士高峰论坛议程重磅发布

OpenI启智社区

人工智能 开源社区 院士峰会 启智开发者大会

谁在驱动、谁在引领?(14/28)

赵新龙

28天写作

持续写作的动力

张老蔫

28天写作

一款好用的Java插件 - Lombok

恒生LIGHT云社区

Java lombok

面向 WEB 开发的 Docker(一)

devpoint

Docker 12月日更

面向WEB开发的Docker(二):什么是Docker、镜像、编排?

devpoint

Docker Dockerfile 12月日更

了解JavaScript新特性:Optional Chaining_大前端_Maya Lekova_InfoQ精选文章