35

了解 JavaScript 新特性:Optional Chaining

 4 years ago
source link: https://www.tuicool.com/articles/IZVJRzA
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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 hardertoread.
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 checksforerrorsandismuch 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 interfacewithan optionalmethod, whichispresent
//onlyforadminusers.
const adminOption = db?.user?.validateAdminAndGetPrefs?.().option;

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

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

复制代码

// Extends the capabilities of the static property access
// with a dynamically generated property name.
constoptionName ='optional setting';
constoptionLength = 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)的常见用例:

复制代码

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

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

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

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

constmiddleName =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.
constfirstNameLength = db.users?.[42]?.names.first.length;

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

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

复制代码

// `db.user`isdeletedonlyif`db`isdefined.
deletedb?.user;

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

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK