可选链: ?. 以安全的方式取访问嵌套的对象属性,即使某个属性根本不存在;
一.解决的问题
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运算符组合使用是不可取的