likes
comments
collection
share

可选链操作符(?.)——开发必备神器

作者站长头像
站长
· 阅读数 2

它的出生

随着现在前后端分离的推进越来越快,现在的日常开发前端往往是自己不需要去数据库操作数据了,只需要通过调用API就可以进行数据获取。这虽然极大的方便了我们的开发,但是随之而来也会伴生各种各样的新问题,比如数据的层次嵌套过深、数据不单一等等一系列原因,使得我们往往需要做很多的逻辑判断。

比如我们在后端拿出了people的数据,想去直接获取它的家庭人口,如果像下面这样子直接获取,可能会有时候能够拿到,有时候因为场景变化就会缺少这个字段,获得ERROR大奖章一枚!

const people = {} // 假设这是后端数据

console.log(people.family.numbers);

可选链操作符(?.)——开发必备神器

js中直接获取不存在的数据是会引发异常,导致整个进程done掉,但是因为一个小小的数据没有导致整个进程done掉很明显不是我们想要的结果,那么我们就要进行一下控制了。在这里解决办法大致分为两种,一种是借助第三方库,第二种就说自己手动拦截了。

  • 第三方库

    在这里我们直接拿lodash来使用,lodash我们要获取一个对象下的数据,往往会使用getter方法

        _.get('people','family.numbers')
    

    在lodash中如果存在我们要获取的key,就会返回该key下的value,即我们想要的numbers,如果不存在,就返回空(顺便我们具体看看他背后做了哪些操作吧)

    //get.js
    function _get(data,f){
       if(f.substr) f = f.split(/\.|\\|\//);
       if(f.length && data){
           return _get(data[f.shift()],f)
       }else if(!f.length && data){
           return data
       }else {
           return "";
       }
    }
    export default function(target,path,defaultValue){
       return _get(target,path,defaultValue);
    }
    
  • 原生自己js手写

    自己手写进行拦截其思路也是极其简单,就是逐层向下判断有没有就行了。

        console.log(people && people.family && people.family.numbers);
    

    当进行逐个判断的时候,一个不存在就会返回undefined,从而避免ERROR,但是相比之下,如果不依赖第三方库的时候,自己写就显得极其复杂了。假设这数据结构的深度不是三层,是5层,10层呢?那是不是就显得极其复杂了?

这是在这个背景之下,我们今天的猪脚——可选操作符?.就出来了!那么使用可选操作符我们又要怎么操作呢?

我们只需在需要判断的的地方使用它就好了呀!

    console.log(people?.family?.numbers); // undefined

就是这么的简单!!!这是这么粗暴!!!只要在需要判断的地方前面,多加一个?就欧了

这么实用的操作,确定不学习吗?

基础使用

官方定义MDN文档:可选链操作符( ?. )允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。?. 操作符的功能类似于 . 链式操作符,不同之处在于,在引用为空(nullish ) (null 或者 undefined) 的情况下不会引起错误,该表达式短路返回值是 undefined。与函数调用一起使用时,如果给定的函数不存在,则返回 undefined。

当尝试访问可能不存在的对象属性时,可选链操作符将会使表达式更短、更简明。在探索一个对象的内容时,如果不能确定哪些属性必定存在,可选链操作符也是很有帮助的。

可选操作符的基础使用其实是极其简单的,就是在可能会因为缺乏字段引起error的地方加上即可。怎么确定从哪里开始会引发这个error呢?

我们还是从那个有(jian)趣(lou)的后端数据讲起吧

const people = {} // 假设这是后端数据

console.log(people); // {}
console.log(people.family); // undefined
console.log(people.family.number); // ERROR

由输出可以看到,其实js本身还是有一定的容错机制的,所以我们只需要在可能会触发容错机制的地方,加上即可!

虽然使用可选操作符很简单,但是还是有很多注意事项的

  1. 可选操作符前面的变量必须声明!如果该操作符前面的变量未声明,那么就会引发error

  2. 不可过度使用,我们只需要在可能会引发error的地方使用就好,?.虽好,可不要贪多哦(官方建议,为啥俺也不知道)

  3. 当遇见null或者undefined就结束(也就是短路)

  4. 可选链不能用于赋值,只能用于判断是否会短路,会短路就返回undefined,否则就返回该key的值(如果想赋默认值,就要使用它的兄弟??)

它的兄弟——空值合并操作符(??)

上文说到,可选操作符是不可以进行赋值操作的,但是它的兄弟可以呀😎,毕竟葫芦娃能吐水的就不能吐火呢

过去

在可选操作符和空值合并操作符出现之前,我们要判断一个一个属性是否存在,存在的时候取出它的值,,不存在的时候赋默认值,我们可能要像下面一样写一长串:

    console.log(people && people.family && people.family.numbers || '不存在');

往往是极其长而麻烦的,但是现在不一样了!

现在

我们只需要将他们两兄弟配合使用即可:

    console.log(people.family?.number ?? '不存在');

只有当前面为null或者undefined的时候,会进行空值合并操作,就是赋予后面设定的默认值。

进阶

前面讲了那么多,都是很基础的用法,接下来让我们一起学习一下骚操作吧!

在js中,对象里面可以包含的东西是很多很多的,所以?.也不仅仅使用在简简单单的判断操作上。他还可以应用到数组、函数等等一系列操作上

语法:

obj?.prop
obj?.[expr]
arr?.[index]
func?.(args)

开始的两个简单的我们已经学习完了,接下来看看数组和函数的吧!

数组

其实arr?.[index]从表达式就可以很清晰的知道,就是获取arr[index]元素。如下:

    let arr = [1, 2, 3];
    console.log(arr?.[5]); // undefined

或许小伙伴们会觉得这个可能很小儿科,就算不用也没问呀,但是如果是下面这种情况呢?

    let demo = { 
    }

    console.log(demo.a[1]);  // ERROR
    console.log(demo.a?.[1]);  // undefined

如果不进行判断不就error了吗?判断那么又要像开篇一样进行一系列枯燥繁琐的判断,但是使用?.不就可以很快速解决这个问题了?

函数

我们要获取的,往往是不仅仅只限于数据,有时候我们可能获取一些API,但是如果不存在对应的API,照样会引发异常,在这里,照样有解决办法!

const demo1 = {
    func() {
        console.log('欸嘿,就不报错!');
    }
}

const demo2 = {

}

demo1.func(); // 欸嘿,就不报错!
demo2.func(); // TypeError: demo2.func is not a function

我们使用可选操作符,就可以完美的避免这个error

const demo1 = {
    func() {
        console.log('欸嘿,就不报错!');
    }
}

const demo2 = {

}

demo1.func?.(); // 欸嘿,就不报错!
demo2.func?.(); // 

可选链操作符(?.)——开发必备神器

但是在这里有一个需要大家注意的点,当判断到存在和函数同名的非函数属性时,会引发异常

const demo1 = {
    func() {
        console.log('欸嘿,就不报错!');
    }
}

const demo2 = {
    func = 'demo'
}

demo2.func?.(); // 

可选链操作符(?.)——开发必备神器

获取很多小伙伴会觉得在数组和函数的应用上会很别扭,但是大家结合一下js的执行机制去理解,就会明白为何要这么写以及为何存在同名非函数会进行报错了

支持情况

其实?.操作符并不是在js独有,目前在C#,Swift都有,而且TS也加入该新特性。在node.js需要升级到14.0以上才支持(但是一般都会使用Babel进行转译,所以完全不用担心啦!)

浏览器支持情况

可选链操作符(?.)——开发必备神器

我是江河,前端实习生一枚,文章如有不正之处,敬请斧正!

面对新事物,我们要勇于拥抱,只有不断接受新事物,将新特性为我们所用,才能不断前进,不断超越!