JS中的 ?? 和 ?. 操作符

235 阅读4分钟

在实习过程中发现项目代码中取值操作中大量使用的是 ?. 以及 ?? 操作符,是我之前没有怎么使用过的,不太了解,所以写篇文章来加深自己的印象。

本文主要参考MDN文档:developer.mozilla.org/zh-CN/docs/…

以及一些其它人的文章

可选链操作符(?.)

概述

可选链操作符( ?. )允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。

其功能类似于 . 链式操作符,不同之处在于,在引用为空 null 或者 undefined 的情况下不会引起错误,该表达式短路返回值是 undefined。与函数调用一起使用时,如果给定的函数不存在,则返回 undefined。

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

const obj = {
  name: 'zyh',
  friends: {
    name: 'erfei'
  }
}
// 可选链操作符
const friendName = obj.friends?.name
console.log(friendName); // erfei
// 普通取值
const testName = obj.friends.name
console.log(testName); // erfei

语法

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

描述

通过连接的对象的引用或函数是 undefined 或 null 时,可选链操作符提供了一种方法来简化被连接对象的值访问

比如存在一个嵌套结构的对象,不使用可选链的话查找一个深度嵌套的子属性时,需要验证之间的引用

let test = obj.first && obj.first.second

这是因为为了避免报错在访问 obj.first.second 之前,要保证 obj.first 的值不是 null 也不是 undefined,而不对 obj.first 进行校验则有可能抛出错误

而在使用可选链操作符(?.)后,访问 obj..first.second 不再需要明确的校验 obj.first 的状态

let test = obj.first?.second

通过使用 ?. 操作符取代 . 操作符,JavaScript 会在尝试访问 obj.first.second 之前,先隐式地检查并确定 obj.first 既不是 null 也不是 undefined。如果obj.first 是 null 或者 undefined,表达式将会短路计算直接返回 undefined。

等价于以下表达式,但实际没有创建临时变量

let temp = obj.first;
let nestedProp = ((temp === null || temp === undefined) ? undefined : temp.second);

作用

1.函数调用

当尝试使用一个不可能存在方法时也可以使用可选链,使表达式自动返回undefined而不是抛出一个异常

2.处理可选的回调函数或者事件处理器

如果使用解构赋值来结构一个对象的回调函数或fetch方法,可能得到不能当作函数直接调用的不存在的值,除非已经校验了存在性。而使用 ?. 可以忽略二外的校验

function dosomething(onContent, onError) {
    try {
        // do something
    } catch(err) {
        if(onError) {
            onError(err.message)
        }
    }
}
// 使用可选链
function dosomething(onContent, onError) {
    try {
        // do something
    } catch(err) {
        onError?.(err.message)
    }
}

3.表达式

当使用方括号与属性名的形式来访问属性时,也可以使用可选链操作符

let test = obj?.['prop' + 'Name']

4.访问数组元素

let arr = arr?.[5]

注意: 可选链不能用于赋值

兼容性

不支持 IE ,其余都支持

空值合并运算符(??)

概述

空值合并运算符是一个逻辑操作符,当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数

语法

leftExpr ?? rightExpr

作用

1.可为常量提供默认值

使用空值合并操作符保证常量不为 null 或者 undefined

const nullValue = null;
const emptyText = ""; // 空字符串,是一个假值,Boolean("") === false
const someNumber = 42;
​
const valA = nullValue ?? "valA 的默认值";
const valB = emptyText ?? "valB 的默认值";
const valC = someNumber ?? 0;
​
console.log(valA); // "valA 的默认值"
console.log(valB); // ""(空字符串虽然是假值,但不是 null 或者 undefined)
console.log(valC); // 42

2.为变量赋默认值

以前为变量赋默认值通常做法使使用逻辑或操作符(||),但逻辑或操作符左侧的操作数会被强制转换成布尔值用于求职,任何价值都不会被返回。这就会导致如果使用 0,' ',NaN 作为有效值时就会出现不可预料的后果

但空值操作符可以避免这种陷阱,其只有在第一个操作数为 null 或 undefined 时返回第二个操作数

3.短路

与 OR 和 AND 逻辑操作符类似,当左表达式不为 null 或 undefined 时,不会对右表达式进行求值

注意:空值合并操作符不能与 AND 或 OR 操作符共用

兼容性

不支持 IE 和 Opera Android,其余都支持

总结

空值合并操作符与可选链操作符存在关系,空值合并操作符针对 undefined 和 null 两个值,可选链操作符也是如此。因此可以在访问属性可能为 undefined 与 null 的对象时,空值合并操作符可以在使用可选链时设置一个默认值