JS 逻辑赋值运算符:||= / &&= / ??= 用法和区别

ES2021 引入了三个逻辑赋值运算符:||=&&=??=。这三个符号都是”条件赋值”的简写,但触发条件各不相同,混淆了容易出 bug。

||=(逻辑或赋值)

只有左侧为 falsy 时才赋值

a ||= b
// 等价于
a = a || b
// 即:if (!a) a = b
let x = null;
x ||= "default";
console.log(x); // "default"

let y = 0;
y ||= 100;
console.log(y); // 100  ← 0 是 falsy,会被覆盖

会触发赋值的值nullundefinedfalse0''NaN

典型用途:缓存计算结果

function checkIsRowVisible(data) {
    viewportRect ||= scrollContainer.getBoundingClientRect();
    // 第一次为 undefined,执行右侧并缓存
    // 之后 viewportRect 有值,跳过
    const rowEl = data._rowEl.getBoundingClientRect();
    return rowEl.bottom >= viewportRect.top && rowEl.top <= viewportRect.bottom;
}

??=(空值合并赋值)

只有左侧为 null 或 undefined 时才赋值

a ??= b
// 等价于
a = a ?? b
// 即:if (a === null || a === undefined) a = b
let x = null;
x ??= "default";
console.log(x); // "default"

let y = 0;
y ??= 100;
console.log(y); // 0  ← 0 不是 null/undefined,不会被覆盖

??=||= 更”精准”:0false'' 都不会触发赋值。

典型用途:对象属性的惰性初始化

user.preferences ??= {};
user.preferences.theme ??= "dark";

&&=(逻辑与赋值)

只有左侧为 truthy 时才赋值

a &&= b
// 等价于
a = a && b
// 即:if (a) a = b
let arr = [1, 2, 3];
arr &&= arr.map(x => x * 2);
console.log(arr); // [2, 4, 6]

let empty = null;
empty &&= [1, 2, 3];
console.log(empty); // null  ← null 是 falsy,不赋值

典型用途:只在值存在时更新

element &&= element.querySelector(".item");
// element 为 null 时不执行,避免报错

三者对比

运算符触发赋值条件不触发的值
||=左侧为 falsytruthy 值
??=左侧为 null/undefined0, false, ”, NaN 等
&&=左侧为 truthyfalsy 值
let a = 0;
a ||= 1;   // a = 1  (0 是 falsy)
a = 0;
a ??= 1;   // a = 0  (0 不是 null/undefined)
a = 0;
a &&= 1;   // a = 0  (0 是 falsy,不赋值)

let b = 5;
b ||= 1;   // b = 5  (5 是 truthy,不赋值)
b ??= 1;   // b = 5  (5 不是 null/undefined,不赋值)
b &&= 10;  // b = 10 (5 是 truthy,赋值)

选哪个

  • 想要”没有值就用默认值”,且 0 / false / '' 也算有效值 → 用 ??=
  • 想要”空/假就用默认值” → 用 ||=
  • 想要”有值才更新” → 用 &&=

对于对象初始化类的场景,??= 更安全,不会意外覆盖 false0 这类合法值。