# 可选链 ?. & 空值合并 ??

# 课程目标

学习使用 可选链 ?.和空值合并符 ??处理对象读取属性的异常情况

# 可选链 ?.

可选链 ?.,是 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.

# 空值合并 ??

在某些情况下,您希望在变量为 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 用户。

  1. 首先确认用户是否为 vip 客户

完成函数 isVip() 判断用户是否为 vip 用户,如果是,就返回 vip 用户的编号。如果不是返回 undefined

  1. 你们系统针对 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'