你可能不知道的 JS 特性:可选链
in 码农技术宅翻译点文章 with 1 comment

你可能不知道的 JS 特性:可选链

in 码农技术宅翻译点文章 with 1 comment

今天我们来介绍一个你可能没见过的 JS 新特性,目前处于 Stage 3 阶段,它叫作 可选链(optional chaining),它可能解决很多人都面对过的痛点,让我们来了解这下~

为什么我们需要它

想象一下你从某个 api 获取数据,返回的对象嵌套了好多层,这就意味着你需要写很长的属性访问:

// API response object
const person = {
    details: {
        name: {
            firstName: "Michael",
            lastName: "Lampe",
        }
    },
    jobs: [
        "Senior Full Stack Web Developer",
        "Freelancer"
    ]
} 
// Getting the firstName
const personFirstName = person.details.name.firstName;

上面的代码很容易产生错误,我们一般会这么改进:

// Checking if firstName exists
if( person &&
    person.details &&
    person.details.name ) {
        const personFirstName = person.details.name.firstName || 'stranger';
}

可以看到为了访问某个人的 firstName,代码变得非常不优雅。我们可以用 lodash 来优化一下:

_.get(person, 'details.name.firstName', 'stranger');

lodash 的写法可读性更高,但是需要引入额外的依赖,而且在团队内部大家可能不会统一都这么写,那么有没有更好的办法呢?

解决方案

可选链 就是为了解决这个问题而诞生的。

用法

可选链在语法上可能看起来比较陌生,但是用了几次之后你就会很容易适应这种写法。

const personFirstName = person?.details?.name?.firstName;

其实就是在属性访问符 . 的前面加了个问号。我们看上面语句中第一个 ?. ,从 JS 层面,它表示如果 person 的值为 null 或者 undefined,就不会报错而返回 undefined,否则才继续访问后面的 details 属性。而如果后面的属性访问链中有任何一个属性为 null 或者 undefined,那么最终的值就为 undefined

默认值

为了优雅地设置默认值,我们引入另外一个特性:空值合并运算符(nullish-coalescing-operator),听起来好像很复杂,其实也很简单:

const personFirstName = person?.details?.name?.firstName ?? 'stranger';

这个运算符就是 ??,如果它左侧表达式的结果是 undefinedpersonFirstName,就会取右侧的 stranger
是不是跟短路运算符 || 很像,那假如我们把 ?? 换成 || 呢?
上面的例子中,如果 firstName 的值为 0 或者空字符串等非 undefinedfalsy 值,那么最终的结果就不一样了。
?? 就是为了取代 || ,来做设置默认值这件事的。

动态属性

如果你需要使用动态属性,同样很简单:

const jobNumber = 1;
const secondJob = person?.jobs?.[jobNumber] ?? 'none';

上面的代码中, jobs?.[jobNumber]jobs[jobNumber] 的含义是一样的,区别就是前者不会报错。

函数或方法调用

同样的,如果想安全调用一个方法,只需要使用 ?.()

const currentJob = person?.jobs.getCurrentJob?.() ?? 'none';

如果 getCurrentJob 不是一个函数,currentJob 的值就是 none

现在就使用这个特性

很显然,这个特性的兼容性感人,不过没关系,我们有 babel!
立刻,马上就能让你使用它:

babel-plugin-proposal-optional-chaining

最后的话

这个特性在很多其他的语言如 C#Swift 中都有实现,并且 TypeScript 中也已经加入该特性。感兴趣的小伙伴还不快尝试一下,如果嫌安装 babel plugin 太麻烦,直接使用 lodash 的 get 也不失为一种保守的选择~

参考链接

JS new feature: Optional Chaining
proposal-optional-chaining
babel-plugin-proposal-optional-chaining
babel nullish-coalescing-operator

Responses
  1. 不错不错

    Reply