ES2020新语法:可选链操作符 `?.`

项目中一个很常见的场景,从接口返回的数据,对象中的某个属性可能不存在,即 undefined ;或者尝试获取 DOM 元素,该元素不存在,即 null 。下面是 MDN 官方的例子,cat 属性可能不存在:

const adventurer = {
  name: 'Alice',
  cat: {
    name: 'Dinah'
  }
};

如果想要访问 catname 属性,像下面这样可能会报错:

const name = adventurer.cat.name

Uncaught TypeError: Cannot read property ‘name’ of undefined 

如果 cat 属性不存在,那么 adventurer.cat 的值就是 undefined 。在 undefined 上访问 name 就会出现上面的报错信息。一旦报错,这段代码的执行就中断了,进而影响其他代码的执行甚至阻塞页面加载。

使用 AND 运算符

为了避免出现报错,项目中常见的作法是这样的:

const name = adventurer && adventurer.cat && adventurer.cat.name

 AND运算符 && 当左边的表达式为 true ,不管右边表达真假,都返回右边的表达式;当左边表达式为 false 直接返回左边的表达式

上面的代码中,查找一个深度嵌套的子属性时,需要验证之间的引用。这样当 cat 属性不存在时,提前进行了返回,从而避免报错。

这样做很明显有个缺点,当访问的属性嵌套了很多层,校验的语句会变得很长,影响代码可读性。

使用可选链操作符

 可选链操作符(?.),在访问子属性之前,不再需要明确地校验当前属性的状态,再并用短路计算获取最终结果:

const name = adventurer?.cat?.name

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

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

let temp = adventurer.cat;
let name = ((temp === null || temp === undefined) ? undefined : temp.name);

可选链常用语法如下:

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

函数调用 

函数调用时如果被调用的方法不存在,使用可选链可以使表达式自动返回undefined而不是抛出一个异常:

let result = someInterface.customMethod?.(); 

对象属性 

可选链用于访问对象属性:

let nestedProp = obj?.first;

 对象属性支持表达式:

let nestedProp = obj?.['prop' + 'Name'];

可选链不能用于赋值

注意:可选链只能用于访问属性,不能用来赋值。

let object = {};
object?.property = 1;

上面这段代码执行会报错:

Uncaught SyntaxError: Invalid left-hand side in assignment

数组元素 

let arr=[23,45,4,56]
console.log(arr?.[1])//45
console.log(arr?.[4])//undefined

短路计算

当在表达式中使用可选链时,如果左操作数是 null 或 undefined,表达式将不会被计算:

let potentiallyNullObj = null;
let x = 0;
let prop = potentiallyNullObj?.[x++];
// 相当于下面代码
// let prop = potentiallyNullObj && x++;
console.log(x); //0 (x 将不会被递增,依旧输出 0)
console.log(prop); //undefined
console.log(potentiallyNullObj ); //null

注意:prop没有被赋值 

连用可选链操作符

可以连续使用可选链读取多层嵌套结构:

let customerCity = customer.details?.address?.city;
let duration = vacations.trip?.getTime?.();

你可能感兴趣的:(前端,ES6,前端)