JavaScript 逻辑赋值运算符:||=、&&=、??= 和可选链动态属性访问

逻辑或赋值 ||=

ES2021 引入的 ||= 只在左侧是 falsy 时才赋值:

viewportRect ||= scrollContainer.getBoundingClientRect();

等价于:

if (!viewportRect) {
    viewportRect = scrollContainer.getBoundingClientRect();
}

常用于”懒初始化缓存”:第一次访问时计算并保存,后续复用已有值,避免重复执行开销大的操作。

触发赋值的 falsy 值:nullundefinedfalse0''NaN

空值合并赋值 ??=

??= 只在左侧是 null 或 undefined 时才赋值:

config.timeout ??= 5000;

等价于:

if (config.timeout === null || config.timeout === undefined) {
    config.timeout = 5000;
}

||= 与 ??= 的区别

let x = 0;
x ||= 10;
console.log(x);  // 10  ← 0 是 falsy,触发了赋值

let y = 0;
y ??= 10;
console.log(y);  // 0   ← 0 不是 nullish,不触发赋值
场景推荐
变量为空对象/数组/字符串时初始化??=
变量为任何假值时初始化`
变量已赋值则不覆盖??=(更安全)

逻辑与赋值 &&=

&&= 只在左侧是 truthy 时才赋值:

user &&= { ...user, lastLogin: Date.now() };
// 仅当 user 存在时才更新

可选链结合动态属性访问

?.[] 是可选链加计算属性的组合:

const currentValue = projection.user_property?.[attrDef.value];

等价于:

const currentValue =
    projection.user_property == null
        ? undefined
        : projection.user_property[attrDef.value];

attrDef.value 是运行时计算的属性名,不能用 ?. 点语法(点语法只能接静态标识符),必须用方括号形式 ?.[]

// 深层链式安全访问
const val = obj?.a?.b?.[dynamicKey]?.value;
// 任何一级为 null/undefined 都返回 undefined,不会抛错