003-JS可选链&空值合并

目录

可选链

示例:

语法:

更多:

可选链和表达式:

可选链不能用于赋值:

可选链访问数组元素:

短路计算

连用可选链运算符

可选链与函数调用

可选链与 nullish 合并运算符:

总结:

空值合并

语法:

为变量赋默认值

短路

不能与 AND 或 OR 运算符共用

总结:


可选链

可选链操作符( ?. )允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。?. 操作符的功能类似于 . 链式操作符,不同之处在于,在引用为空(nullish ) (null) 或者 undefined) 的情况下不会引起错误,该表达式短路返回值是 undefined。与函数调用一起使用时,如果给定的函数不存在,则返回 undefined

示例

const adventurer = {
  name: 'Alice',
  cat: {
    name: 'Dinah',
  },
};
​
const dogName = adventurer.dog?.name;
console.log(dogName); // undefined
console.log(adventurer.someNonExistentMethod?.()); // undefined

当尝试访问可能不存在的对象属性时,可选链运算符将会使表达式更短、更简明。通过连接的对象的引用或函数可能是 undefinednull 时,可选链运算符提供了一种方法来简化被连接对象的值访问。

const user = {
    details: {
        name: 'sunrise',
        contact: {
            email: 'sunrise@example.com'
        }
    }
};
// 传统方法访问 email
let email = '';
if (user && user.details && user.details.contact) {
    email = user.details.contact.email;
} else {
    email = 'No email available';
}
console.log(email); // 输出: sunrise@example.com
​
// 使用可选链访问 email
const email = user?.details?.contact?.email || 'No email available';
console.log(email); // 输出: sunrise@example.com

语法

obj.val?.prop
obj.val?.[expr]
obj.func?.(args)

更多:

可选链和表达式:

当使用方括号与属性名的形式来访问属性时,你也可以使用可选链运算符:

let nestedProp = obj?.["prop" + "Name"];
可选链不能用于赋值:
let object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment
可选链访问数组元素:
let arrayItem = arr?.[42];
短路计算

当在表达式中使用可选链时,如果左操作数是 nullundefined,表达式将不会被计算

let potentiallyNullObj = null;
let x = 0;
let prop = potentiallyNullObj?.[x++];
​
console.log(x); // x 将不会被递增,依旧输出 0
连用可选链运算符

可以连续使用可选链读取多层嵌套结构:

let customer = {
  name: "sunrise",
  details: {
    age: 21,
    location: "Paradise Falls", // details 的 address 属性未有定义
  },
};
let customerCity = customer.details?.address?.city;
​
// … 可选链也可以和函数调用一起使用
let duration = vacations.trip?.getTime?.();
可选链与函数调用
const utils = {
    stringUtils: {
        toUpperCase(str) {
            return str.toUpperCase();
        }
    }
};
​
// 使用可选链进行函数调用
const result = utils?.stringUtils?.toUpperCase('hello world');
​
console.log(result); // 输出: HELLO WORLD

如果 utils.stringUtils 不存在,utils?.stringUtils.toUpperCase('hello world') 将返回 undefined 而不是抛出错误。

可选链与 nullish 合并运算符:
const user = {
    details: {
        name: 'sunrise',
        // contact属性可能不存在
    }
};
​
// 使用可选链和 nullish 合并运算符
const contactEmail = user?.details?.contact?.email ?? 'No email available';
​
console.log(contactEmail); // 输出: No email available

如果 user.details.contact.email 链中的任何部分不存在,将返回 'No email available'

总结

可选链是一种强大的工具,它允许你编写更少的代码来处理深层对象属性,同时避免了可能的错误。它使代码更干净、更易于维护,特别是在处理复杂的数据结构时。

空值合并

空值合并运算符??)是一个逻辑运算符,当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数。

与逻辑或运算符(||)不同,逻辑或运算符会在左侧操作数为假值时返回右侧操作数。也就是说,如果使用 || 来为某些变量设置默认值,可能会遇到意料之外的行为。比如为假值(例如,''0)时

示例

const foo = null ?? 'default string';
console.log(foo);//  "default string"
​
const baz = 0 ?? 42;
console.log(baz);//  0

语法:

let value = a ?? b;

如果 anullundefined,则 value 将被赋值为 b。如果 a 为任何其他假值(如 0false 或空字符串 ''),则 value 将被赋值为 a

在没有空值运算符之前,我们通常使用逻辑或 || 运算符来提供一个默认值,但逻辑或运算符会将所有假值(如 0false''NaN)都替换为默认值。

使用空值运算符,我们可以确保仅在值为 nullundefined 时才使用默认值。

const user = {
    name: 'sunrise',
    age: 0,  
    contact: {
        email: undefined
    }
};
​
// 传统方法访问 email
let email = user.contact && user.contact.email || 'default@email.com';
console.log(email); // 输出: default@email.com
​
// 使用空值运算符访问 email
const email = user.contact?.email ?? 'default@email.com';
console.log(email); // 输出: default@email.com

由于 user.contact.emailundefined,因此使用了默认值。但是,如果 email 是一个有效的空字符串,逻辑或运算符也会替换它。

如果 user.contact.emailnullundefinedemail 将被赋值为 'default@email.com'。但是,如果 user.contact.email 是一个空字符串,它将被保留,因为空字符串不是 null 也不是 undefined

为变量赋默认值

以前,如果想为一个变量赋默认值,通常的做法是使用逻辑或运算符(||):

let foo;
​
//  foo is never assigned any value so it is still undefined
let someDummyText = foo || "Hello!";

然而,由于 || 是一个布尔逻辑运算符,左侧的操作数会被强制转换成布尔值用于求值。任何假值(0''NaNnullundefined)都不会被返回。这导致如果你使用0''NaN作为有效值,就会出现不可预料的后果。

let count = 0;
let text = "";
​
let qty = count || 42;
let message = text || "hi!";
console.log(qty); // 42,而不是 0
console.log(message); // "hi!",而不是 ""

空值合并运算符可以避免这种陷阱,其只在第一个操作数为nullundefined 时(而不是其他假值)返回第二个操作数:

let myText = ""; // An empty string (which is also a falsy value)
​
let notFalsyText = myText || "Hello world";
console.log(notFalsyText); // Hello world
​
let preservingFalsy = myText ?? "Hi neighborhood";
console.log(preservingFalsy); // '' (as myText is neither undefined nor null)

短路

与 OR 和 AND 逻辑运算符相似,当左表达式不为 nullundefined 时,不会对右表达式进行求值。

function A() {
  console.log("函数 A 被调用了");
  return undefined;
}
function B() {
  console.log("函数 B 被调用了");
  return false;
}
function C() {
  console.log("函数 C 被调用了");
  return "foo";
}
​
console.log(A() ?? C());
// 依次打印 "函数 A 被调用了"、"函数 C 被调用了"、"foo"
// A() 返回了 undefined,所以运算符两边的表达式都被执行了
​
console.log(B() ?? C());
// 依次打印 "函数 B 被调用了"、"false"
// B() 返回了 false(既不是 null 也不是 undefined)
// 所以右侧表达式没有被执行

不能与 AND 或 OR 运算符共用

?? 直接与 AND(&&)和 OR(||)运算符组合使用是不可取的。(应当是因为空值合并运算符和其他逻辑运算符之间的运算优先级/运算顺序是未定义的)这种情况下会抛出 SyntaxError

null || undefined ?? "foo"; // 抛出 SyntaxError
true || undefined ?? "foo"; // 抛出 SyntaxError

但是,如果使用括号来显式表明运算优先级,是没有问题的:

(null || undefined) ?? "foo"; // 返回 "foo"

总结:

空值合并运算符提供了一种更精确的方法来处理可能为 nullundefined 的值,同时保留其他假值。这使得它在处理具有默认值的变量时比逻辑或运算符更安全、更灵活。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值