【es新特性】你还在写无穷无尽的 && 吗?可选链帮你精简代码!

3,653 阅读2分钟

故事的开始

阿龙最近遇到个需求,在做购物车需求的时候,有些用户的购物车没有添加任何商品,如果直接去取后端返回的vo里面的list(购物车列表)属性循环时,会报错,导致后续逻辑无法执行

后端返回数据格式如下:

// 空数据时
{
    code:200,
    message:'success',
    result:{
        shoppingCartVo:{
            list:null,
            cartSize:null,
            totalPrice:null,
            ...
        }
    }
}

// 存在数据时
{
    code:200,
    message:'success',
    result:{
        shoppingCartVo:{
            list:[{xxx:xxx}],
            cartSize:999,
            totalPrice:999,
            ....
        }
    }
}

snippet-1:不进行判断,代码如下(报错)

if(result.shoppingCartVo){
    result.shoppingCartVo.list.forEach(()=>{}) //Uncaught TypeError: Cannot read properties of null (reading 'list') // 不能在null上读取list属性
}

snippet-2:按照正常的逻辑进行判断,代码如下

if(result.shoppingCartVo && result.shoppingCartVo.list && result.shoppingCartVo.list.length){
    // 开始做循环操作
}

可以看到上面的代码非常多的 && ,非常的不直观,日积月累,这对项目的可维护性是非常不利的。

主角登场

可选链操作符,先看看它的写法?.,再看看MDN对它的定义。

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

也就是说,如果取一个不存在的值,使用这个语法不会报错,不影响代码执行,这就是我想要的!

话不多说,开始对上述snippet-2进行改造

if(result.shoppingCartVo?.list){
    // 开始循环逻辑,如果用户购物车没有数据,则判断条件会返回undefined,就不会进入判断
    console.log('~')
}

扩展

看了MDN,发现这个语法不止可以用在对象,也可以用在数组甚至是函数上。

数组

需求,我想给list下标为1的元素赋值为 'hello' 数组如下

let list = [1,2,3]
  • 不使用可选链
// 判断list存在,且length属性大于0,且下标为1的元素存在
if(list && list.length && list[1] !== undefined){
    list[1] = 'hello'
}
  • 使用可选链
if(list?.[1]){
    list[1] = 'hello'
}

函数

需求:如果函数名的fn的函数有函数体,就执行该函数

  • 不使用可选链
fn && fn()
  • 使用可选链
fn?.()

总结

具体兼容性可参见 caniuse