Oasis's Cloud

一个人的首要责任,就是要有雄心。雄心是一种高尚的激情,它可以采取多种合理的形式。
—— 《一个数学家的辩白》

为什么用 ?? 而不是 ||?空值合并运算符详解

作者:oasis


JS 除了支持可选链运算符?.外,还提供空值合并运算符??。通过使用可选链和空值合并运算符可以大幅简化判断条件的书写方式。

例如

const user = {
    name: 'oasis-cloud'
}

if(user && user.name) {
    console.log(user.name)
}
const country = user && user.country ? user.country : 'China' 

例子中的条件判断需要多写一些代码。通过可选链和空值合并运算符,可以简化写法。

const user = {
    name: 'oasis-cloud'
}

if(user?.name) {
    console.log(user.name)
}
const country = user?.country ?? 'China' 

空值合并运算符表达的意思是: 变量不是 null 和 undefined 就返回变量自身,否则返回备选值。

?? 与 || 的区别

空值合并运算符 ?? 与逻辑或运算符 || 的区别在于,|| 会把所有假值(false、0、’‘、null、undefined、NaN)都视为”空”,而 ?? 只把 null 和 undefined 视为”空”。

const value = 0;
console.log(value || 'default');  // 'default' (0 被当作假值)
console.log(value ?? 'default');  // 0 (0 不是 null/undefined)

const empty = '';
console.log(empty || 'default');  // 'default'
console.log(empty ?? 'default');  // ''

const falsy = false;
console.log(falsy || 'default');  // 'default'
console.log(falsy ?? 'default');  // false

当需要区分”空值”(null/undefined)和”假值”(0、’‘、false)时,应该使用 ??

运算符优先级

?? 不能直接与 ||&& 一起使用,会报语法错误。必须用括号明确优先级。

// 错误:Uncaught SyntaxError: Unexpected token '||'
const a = 1
const b = 1
const c = 1
const result = a ?? b || c;

// 正确
const result1 = (a ?? b) || c;
const result2 = a && (b ?? c);

短路求值

?? 是短路运算符,当左侧不是 null 或 undefined 时,不会计算右侧表达式。

function getDefault() {
    console.log('getDefault called');
    return 'default';
}

const value = 'hello';
console.log(value ?? getDefault());  // 'hello',不会调用 getDefault

void 0 的原因

可以通过 babel 来看编译后的代码: online-code

var _user$country;
const user = {
  name: 'oasis-cloud'
};
if (user !== null && user !== void 0 && user.name) {
  console.log(user.name);
}
const country = (_user$country = user === null || user === void 0 ? void 0 : user.country) !== null && _user$country !== void 0 ? _user$country : 'China';

在查看 babel 编译后的代码,可以发现,null 采用了字面值,为什么 undefined 要通过 void 0 来获取呢?

MDN文档中,可以看到 null 属于关键字。

而 undefined 属于全局变量,可能会被污染,导致无法获取正确的 undefined。 void 关键字是对表达式求值后返回真正的 undefined,所以更安全。