复合赋值运算符本质省去的是左操作数的重复求值,而非单纯字符数;如 a += b 仅计算 a 一次并原地更新,而 a = a + b 会两次读取 a,对复杂左值(数组元素、getter 属性等)影响显著。

复合赋值运算符到底省了哪几个字符?
它省的不是字符数,而是重复变量名和冗余求值。比如 a = a + b 和 a += b 表面只少写 3 个字符,但关键在于:前者会两次读取 a(一次取值、一次赋值目标),后者只需一次读取 + 原地更新,对复杂左值(如数组元素、对象属性、带 getter 的属性)影响明显。
常见误用是以为 a += b 等价于 a = a + b 在所有上下文都成立——其实不成立:
-
a是let或const声明时,a += b是合法赋值;但若a是只读属性(如Object.defineProperty(obj, 'x', { writable: false })),a += b会静默失败或抛TypeError,而a = a + b明确报错更易调试 - 字符串拼接中
s += 'x'比s = s + 'x'少一次字符串拷贝(V8 等引擎会优化为 in-place 扩容)
哪些类型支持 += 却不支持 ++/--?
++ 和 -- 只适用于数字,但 +=、-=、*=、/= 等在多数语言中会尝试类型转换或重载。JavaScript 尤其典型:
-
str += 'hello'→ 字符串拼接(即使str初始是null或undefined,也会转成字符串) -
num += '2'→ 若num是数字,结果是字符串'52'(因为+优先字符串连接) -
arr.push(x)不能用+=替代,但arr.length += 1合法(不过不推荐,语义不清)
Python 不支持 += 对不可变对象(如 str, tuple)原地修改,但会创建新对象并重新绑定——这点和 JS 不同,JS 的 += 对字符串始终新建。
嵌套对象属性用 += 容易踩什么坑?
直接写 obj.user.profile.age += 1 看似简洁,但一旦中间某层为 null 或 undefined,就会立即抛 TypeError: Cannot read property 'profile' of undefined。它不会像 obj?.user?.profile?.age = (obj?.user?.profile?.age || 0) + 1 那样安全。
更隐蔽的问题是副作用:如果 obj.user 是 getter,每次访问都触发计算,那么 obj.user.profile.age += 1 会调用 getter 两次(读取旧值 + 写入新值),而手动拆解可控制调用次数:
const user = obj.user; // 仅一次 getter
if (user && user.profile) {
user.profile.age = (user.profile.age || 0) + 1;
}
复合赋值在循环里真能提升性能吗?
现代 JS 引擎(V8、SpiderMonkey)对 i += 1 和 i = i + 1 几乎无差别,但对以下场景仍有实际收益:
- 大数组累加:
sum += arr[i]比sum = sum + arr[i]在某些引擎中减少临时 Number 对象创建 - 频繁 DOM 属性更新:
el.style.left += 'px'(需确保初始值已设,否则可能得到'auto px') - WebAssembly 或 Rust 中的
+=可直接映射到单条 CPU 指令(如add),而显式赋值可能多一次 load
真正容易被忽略的是可读性权衡:用 count *= 2 表达“翻倍”很自然,但用 flags |= FLAG_A(位或赋值)处理标志位时,若团队不熟悉位运算,反而增加维护成本。










