# 可选链 ?. & 空值合并 ??
# 课程目标
学习使用 可选链 ?.和空值合并符 ??处理对象读取属性的异常情况
# 可选链 ?.
可选链 ?.,是 ES2020 中引入的一个新特性。
可选链接改变了从深度嵌套对象访问属性的方式。它解决了在 JavaScript 中访问一长串对象属性时必须进行多次 null 检查的问题。
假设有以下对象:
obj = {
prop1: {
prop2: {
someProp: "value",
},
},
};
在 JavaScript 中访问对象中不存在的键会返回 undefined,如果您继续尝试访问嵌套值并且父键不存在,那么会导致TypeError: Cannot read property ... of undefined
错误。因此您在访问对象时,必须先判断键是否存在,存在才继续访问,你会经常看见如下形式代码:
obj.prop1 && obj.prop1.prop2 && obj.prop1.prop2.someProp;
可见,上述代码十分冗长。可选链正是解决了这一问题。它让我们将上面的整个代码重构为以下内容:
obj.prop1?.prop2?.someProp;
如果其中一个属性是 null 或 undefined,则可选链?.将停止读取您要求它读取的属性并返回 undefined.
- 可选链 | MDN (opens new window)
- 可选链 "?." | javascript 现代教程 (opens new window)
- How to Use JavaScript Optional Chaining (opens new window)
# 空值合并 ??
在某些情况下,您希望在变量为 null 或 undefined 的情况下应用默认值。空值合并 ??,就是为了解决这一问题而诞生的。
过去为了实现上面功能,我们最常使用的是三元运算符或者通过使用或运算符(||)的惰性求值来完成:
let amount = null;
amount = amount || 1; // => 1 ,符合预期 ✅
amount = undefined;
amount = amount || 1; // => 1,符合预期 ✅
amount = 0;
amount = amount || 1; // => 1,但是我们希望是0 ❎
amount = "";
amount ? amount : 1; // => 1,但是我们希望是'' ❎
但这样存在一个问题,变量为假的所有情况(例如''or 0)都将应用默认值,而不仅仅是当它为 null 或 undefine 时。
这时,空值合并 ?? 就可以大显身手了,改写上面代码:
let amount = null;
amount = amount ?? 1; // => 1,符合预期 ✅
amount = 0;
amount = amount ?? 1; // => 0,符合预期 ✅
amount = "";
amount = amount ?? 1; // => '',符合预期 ✅
这样就是实现了,变量为 null 或 undefined 的情况下应用默认值,而 变量取值为 ''以及 0 时,默认值不起作用。
# 任务
假设您的工作是提供和维护快递业务的 IT 系统部分。特别是,您负责管理 vip 用户。
- 首先确认用户是否为 vip 客户
完成函数 isVip() 判断用户是否为 vip 用户,如果是,就返回 vip 用户的编号。如果不是返回 undefined
- 你们系统针对 vip 用户有翻译功能,需要获取 vip 用户国籍,显示对应国家语言。
完成获取 vip 用户地址。完成函数 getCountry()。返回 country 信息,如果 country 不存在就默认设置为China
。
请使用今天学习的知识来完成,不要使用 if 语句
let vip_customer_1 = {
name: "Carl",
vip: {
num: "C-1001",
country: "USA",
},
};
let vip_customer_2 = {
name: "Carl",
vip: {
num: "C-1001",
},
};
let customer = {
name: "Jennie",
};
/**
* @param {object} customer
* @param {object} [customer.vip]
* @param {last} [customer.vip.country]
*/
const isVip = ()=>{
// your code here
}
//用例
isVip(vip_customer_1) // => 'U-1001'
isVip(vip_customer_2) // => 'C-1002'
isVip(customer) // => 'undefined'
/**
* @param {object} customer
* @param {object} [customer.vip]
* @param {last} [customer.vip.country]
*/
const getCountry = (customer) => {
//you code here
};
//用例
getCountry(vip_customer_1); // => 'USA'
getCountry(vip_customer_2); // => 'China'