原文地址:https://dev.to/bhagatparwinder/optional-chaining-1a1f
简介
JavaScript 中获取对象属性是一个常见操作,多数时候这些属性是嵌套的。当你从一个不存在的对象上获取属性的时候,JavaScript 就会报错。
让我们来举一些例子来帮助理解:
const myObject = {
name: "Parwinder",
car: "Cybertruck",
age: 42,
computers: {
first: {
name: "iMac",
year: 2017,
spec: {
cpu: "i7",
ram: "16GB"
}
},
second: {
name: "MacBook Pro"
}
}
}
console.log(myObject.computers.first.spec.cpu); // i7
console.log(myObject.computers.second.spec.cpu); // Cannot read property 'cpu' of undefined
第一条日志通过巡查对象来获取我第一台电脑上的 CPU,当同样的方法用在第二台电脑上时就报错。
当 spec 不存在时我们依旧在尝试获取 spec 上的 cpu,cpu 在对象的第五层它前面的任何一层都有可能为 null 或 undefined。
我们通过 if 语句配合 && 操作符来解决此问题:
if(myObject && myObject.computers && myObject.computers.second && myObject.computers.second.spec) {
console.log(myObject.computers.second.spec.cpu);
}
及时上面的脚本可以正确运行,但代码不够整洁。有太多的代码来校验 null / undefined 。
可选链通过 ?.
来表示,它可以用于对象上的键和表达式、数组索引以及对象上的函数。
对象的属性应用可选链
我们可以使用可选链来重写上面的 if 语句:
myObject?.computers?.second?.spec?.cpu // undefined
// Concise and easy to read code
// or
myObject.computers.second.spec?.cpu
?.
操作符可以把对象上的属性进行短路求值。可选链不是通过继续求值来返回错误,而是一旦发现链中的第一个 undefined 或 null,就立即终止,并返回 undefined。
?.
只在它使用的地方起作用。
在 myObject.computers.second.spec?.cpu
中的前三个属性都必须存在,这里只有 spec
引用了可选链,若 spec
不存在才返回 undefined
。
前面三个任何一个属性缺失都会报错,所以只在属性可能存在或不存在的地方使用?.
。若代码中各处使用会导致静默失败而且很难定位调试。
例如:若 computers
是可选的,但是 myObject
是一定会存在的,那应该写成下面:
myObject.computers?.
而不是:
myObject?.computers?.
对象的表达式应用可选链
我们在通过字面量或中括号来获取对象属性时依旧可以使用可选链。
console.log(myObject.computers.second?.["spec"].cpu); // undefined
console.log(myObject.computers.first?.["spec"].cpu); // i7
对象的函数应用可选链
我们在对象上添加一个函数:
const myObject = {
name: "Parwinder",
car: "Cybertruck",
age: 42,
getAge: function () {
return this.age;
}
}
console.log(myObject.getAge()); // 42
如果函数是可选的,我们可以加入可选链。
console.log(myObject.getAge?.());
可选链会确保 JavaScript 视图执行一个不存在的函数,但由于 ?.
提供的短路操作实际上调用永远不会发生。
对象上的数组应用可选链
const names = ["Parwinder", "Lauren", "Leah", "Robert", "Eliu"];
console.log(names[3]); // Robert
const newEmployee = names?.[3]; // Check if names exists
console.log(newEmployee); // Robert
注意:可选链不能应用在赋值的左侧。
let myObject = {};
myObject?.name = "Parwinder"; // Uncaught SyntaxError