ES6之可选链

155 阅读4分钟

可选链: ?.  以安全的方式取访问嵌套的对象属性,即使某个属性根本不存在;

 

一.解决的问题

1. 深度访问对象属性时,当中间属性非必须字段时,就无法安全的访问地址的某一个属性;

let user = {}; // 用户可能没有填地址

alert(user.address.street); // 报错,因为user没有address属性,user.address为undefined,再访问address.street会报错:undefined上没有street属性

 

2. 获取DOM元素,然后获得该DOM元素的innerHTML值,但是该DOM元素不存在,JS会报错;

let html= document.querySelector(‘.my-select’).innerHTML;// 报错,因为querySelector拿到的DOM元素为null,js无法从null上拿到innerHTML值

 

一般可以使用逻辑与运算符解决:

let user = {}; // 用户可能没有填地址

alert(user.address && user.address.street);

 

二.基础用法

当可选链 ?. 前面的值为undefined或null时,会立即阻止代码的执行,并返回undefined;

let user = {}; // 用户可能没有填地址

alert(user.address?.street); // undefined,不会报错,因为可选链判断到user的address为undefined,就不会再继续访问address上的street属性,而是直接返回undefined值

 

并且即便user就是空对象null,基于可选链访问其地址属性也不会报错:

let user = null // 空对象

alert(user?.address); // undefined

alert(user?.address?.street); // undefined

alert(user?.address.street); // undefined

 

注意:****

(1) 可选链不可过度使用,一般仅在某个值可能不存在时使用,例如上述user对象必须存在,但是其上address属性可选,因此访问user的address属性时可不用可选链,即alert(user.address?.street) 更合适,并且还能快速定位因为其他原因导致user对象为undefined或null的情况

(2) 可选链前面的变量必须被显示声明(let/const/var等进行声明),若user变量未被声明,则user?.anything会触发语法错误:user是未定义的;也即可选链对未声明变量无效;

 

三. 其他用法

1. 短路

可选链前面变量值为null或undefined时,会立即停止执行;因此,如果其后存在函数调用或者其他操作,都不会执行

let user = null // 空对象

let x= 0

user?.sayHi(x++); // 什么都不操作,并且输出值是undefined

console.log(x) // 0,x的值没有自增,因为?.判断出来user为null,会立即停止后续执行,x即没有自增,因此仍然为初始值

 

2. ?.():用于执行一个不可能存在的函数

let user1 = { output(){console.log(‘user1’)} };

let user2 = { };

user1.output?.(); // 输出user1,执行output方法

user2.output?.(); // 输出undefined,因为对象user2上没有output方法

 

分析:

user1.,user2.可以访问对象的属性,因为user1和user2都存在,因此能够安全读取;

?.() :根据可选链,首先检查其左边部分output是否不是null或undefined,不是则调用output方法;否则就立刻停止执行,此时会默认输出undefined;

 

3. ?[]:?.可以用于在需要使用中括号访问属性时使用,基于可选链可以安全访问一个空对象的任意属性

let user1 = { name:’user1’ };

let user2 = { };

user1?.[‘name’]; // 输出user1

user2?.[‘name’]; // 输出undefined,因为对象user2上没有output方法

 

4. ?. 可以和delete操作符共用

delete user?.name // 首先判断user对象是否存在name属性,存在则从user上删除name属性

5. ?. 可进行删除和读取操作,但是不能进行赋值

let user = null;

user?.name = ‘user’ // Error,不生效

 

四. 总结

可选链 ?. 存在三种形式:

obj?.prop:如果obj上存在prop属性,则返回prop属性值;否则返回undefined;

obj?.[prop] :同第一种形式,当obj存在prop属性,则返回prop值,否则返回undefined;

obj.method?.() :如果obj.method方法存在则调用obj.method方法,否则返回undefined

 

上面几种形式都是用于检查可选链?.运算符左侧的值是否为null或undefined,如果不是就继续执行,否则直接返回undefined;并且应该仅在 ?.  左侧值可能不存在情况下使用

【注意】可选链在使用时,需要保证运行环境支持该特性,可以通过Babel等工具来进行转译。

 

 

空值合并操作符:??

当左侧操作数值为null或者undefined时,返回其右侧操作数,否则返回左侧操作数;

a ?? b:a是需要检查的值,b为默认值;若a为null或undefined,则返回b否则返回a;

const res1 = foo  ||  ‘default’

const res2 = foo  ??  ‘default’

若foo值为null或undefined,则res1和res2都是default;

若foo值为0,false或者空串’’时,res1仍然是’default’,但是res2就是foo的值;

【注意】和逻辑或运算符不同,逻辑或运算符会在左侧操作数为假(null,undefined,false,0,’’)时,返回操作符右侧表达式的值;但是空值合并运算符只会在左侧值为null或undefined时,才返回右侧表达式的值。

 

空值合并运算符和逻辑AND、OR运算符相似,当左表达式值不是null或undefined时,不会对右侧表达式进行求值;

?? 不能和AND或OR运算符共用,将 ?? 直接和AND和OR运算符组合使用是不可取的