?? 空值合并操作符
1.定义
空值合并操作符(??)是一个逻辑操作符,当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否侧返回左侧操作数。
const foo = null ?? 'undefined'
console.log(foo) // undefined
const baz = 0 ?? 42
console.log(baz) // 0
const nullValue = null;
const emptyText = ""; // 空字符串,是一个假值,Boolean("") === false
const someNumber = 42;
const valA = nullValue ?? "valA 的默认值";
const valB = emptyText ?? "valB 的默认值";
const valC = someNumber ?? 0;
console.log(valA); // "valA 的默认值"
console.log(valB); // ""(空字符串虽然是假值,但不是 null 或者 undefined)
console.log(valC); // 42
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)
// 所以右侧表达式没有被执行
2. 跟逻辑或操作符(||)的区别:
- 逻辑或操作符会在左侧操作数为假值时返回右侧操作数。因为 || 是一个布尔逻辑运算符,左侧的操作数会被强制转换成布尔值用于求职。任何的假值(0, '', NaN, null, undefined)都不会被返回。所以如果使用0, ''或 NaN 作为有效值,就会出现不可预料的后果。而空置合并操作符可以避免这种陷阱,其只在第一个操作数为 null 或 undefined 时(而不是其他假值)返回第二个操作数。
let myText = '';
let myfalsyText1 = myText || 'initValue';
let myfalsyText2 = myText ?? 'initValue';
console.log(myfalsyText1) // initValue
console.log(myfalsyText2) //
3. ?? 不能与 AND(&&) 或 OR(||) 操作符共用
- 应当是空值合并操作符和其他逻辑操作符之间的运算优先级/运算顺序是未定义的,共用会抛出 SyntaxError
null || undefined ?? "foo"; //抛出 SyntaxError
true || undefined ?? "foo"; //抛出 SyntaxError
- 但是,如果使用括号来表示运算优先级,是没有问题的:
(null || undefined) ?? "foo" //foo
?. 可选链操作符
1.定义
可选链操作符(?.)允许读取位于链接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。
const adventurer = {
name: 'Alice',
cat: {
name: 'David',
}
};
const dogName = adventurer.dog?.name
console.log(dogName) //undefined
//通过使用 ?. 操作符取代 . 操作符,,Javascript会在尝试访问 adventurer.dog.name 前,先隐式地检查并确定 adventurer.dog 既不是 null 也不是 undefined。如果 adventurer.dog 是 null 或 undefined,表达式将会短路计算直接返回 undefined。
?? 和 ?. 的关系
两者都是针对 undefined 和 null 两个值。
let foo = { someFooProp: "hi" };
console.log(foo.someFooProp?.toUpperCase()); // "HI"
console.log(foo.someBarProp?.toUpperCase()); // undefined
let customer = {
name: "Carl",
details: { age: 82 }
};
let customerCity = customer?.city ?? "暗之城";
console.log(customerCity); // “暗之城”