你真的会使用这些运算符吗?

179 阅读4分钟

你真的会使用这些运算符吗?

个人主页:康师傅前端面馆


在 Stack Overflow 上,每天有上千个提问源于对 +++==+ 的误解;面试里,一段看似简单的 x++ + ++x 就能让候选人当场沉默。本文用 5 分钟带你彻底搞懂这些“老熟人”——自增、自减与复合赋值运算符——到底做了什么、何时做、以及怎样避免那些隐藏的地雷。读完你会发现,它们不仅能让代码更短,也能让 Bug 更少。

1. 自增自减运算符 (++ / --)

1.1 基本概念

自增 (++) 和自减 (--) 是一元运算符,用于将变量的值增加或减少 1。

1.2 前缀形式 vs 后缀形式

  • 前缀形式:先增加/减少变量的值,然后返回新值
  • 后缀形式:先返回原值,然后增加/减少变量的值
let a = 5;
let b = 5;

// 前缀形式
console.log(++a); // 输出: 6 (先增加,再返回)
console.log(a);   // 输出: 6

// 后缀形式
console.log(b++); // 输出: 5 (先返回,再增加)
console.log(b);   // 输出: 6

1.3 注意事项

  • 只能应用于变量,不能用于字面量或表达式
  • 对于非数值类型的变量,会尝试转换为数字后再进行运算
let str = "5";
console.log(++str); // 输出: 6 (字符串 "5" 转换为数字 5 后加 1)

let bool = true;
console.log(++bool); // 输出: 2 (布尔值 true 转换为数字 1 后加 1)

1.4 易出错点

// 错误示例 - 不能用于字面量
++5; // SyntaxError: Invalid left-hand side expression in prefix operation

// 复杂表达式中的行为可能令人困惑

// 先计算后赋值
let a = 1;
let b = ++a;
console.log(a); // 输出: 2
console.log(b); // 输出: 2

// 先赋值后计算
let a = 1;
let b = a++;
console.log(a); // 输出: 2
console.log(b); // 输出: 1

// 混合运算
let x = 1;
let y = ++x + x++; // 结果是 4,因为:
// 1. ++x 先将 x 增加到 2,表达式的这部分值为 2
// 2. x++ 使用当前 x 的值 2,然后将 x 增加到 3
// 3. 最终结果是 2 + 2 = 4

console.log(y); // 输出: 4
console.log(x); // 输出: 3

2. 复合赋值运算符 (+=, -=, *=, /=, %=, **= 等)

2.1 基本概念

复合赋值运算符是赋值运算符和算术运算符的组合,使代码更加简洁。

2.2 += 运算符

+= 运算符将右操作数加到左操作数上,并将结果赋值给左操作数。

let a = 5;
a += 3; // 等价于 a = a + 3
console.log(a); // 输出: 8

// 字符串连接
let str = "Hello";
str += " World"; // 等价于 str = str + " World"
console.log(str); // 输出: "Hello World"

2.3 其他复合赋值运算符

let x = 10;

x -= 3;  // 等价于 x = x - 3;  结果: 7
x *= 2;  // 等价于 x = x * 2;  结果: 14
x /= 2;  // 等价于 x = x / 2;  结果: 7
x %= 3;  // 等价于 x = x % 3;  结果: 1
x **= 3; // 等价于 x = x ** 3; 结果: 1

2.4 注意事项

  • 左操作数必须是可赋值的引用(变量、对象属性等)
  • 右操作数会被转换为适当的类型进行运算
let obj = { value: 5 };
obj.value += 10; // 对象属性也可以使用复合赋值运算符
console.log(obj.value); // 输出: 15

3. =+ 运算符误解澄清

3.1 实际含义

=+ 并不是一个独立的运算符,而是赋值运算符 = 和一元正号运算符 + 的组合。

let a = "5";
let b = +a; // 将字符串 "5" 转换为数字 5
console.log(b); // 输出: 5
console.log(typeof b); // 输出: "number"

// 等价于
let c = Number(a);
// 或
let d = parseInt(a);

3.2 常见用途

常用于将字符串转换为数字:

let userInput = "123";
let number = +userInput; // 快速转换为数字

// 在表单处理中很常见
let ageInput = document.getElementById("age").value; // 字符串
let age = +ageInput; // 转换为数字

3.3 特殊情况

console.log(+"5");     // 输出: 5
console.log(+"3.14");  // 输出: 3.14
console.log(+"hello"); // 输出: NaN
console.log(+true);    // 输出: 1
console.log(+false);   // 输出: 0
console.log(+null);    // 输出: 0
console.log(+undefined); // 输出: NaN

4. 运算符优先级

了解运算符优先级对于正确编写表达式至关重要:

let a = 2;
let b = 3;

// ** 运算符优先级高于乘法
console.log(2 * 3 ** 2); // 输出: 18 (等价于 2 * (3 ** 2))

// ++ 前缀形式优先级高于 +
let x = 1;
let y = 2;
console.log(++x + y); // 输出: 4 (等价于 (++x) + y)

// += 优先级低于大多数运算符
let z = 5;
z *= 2 + 3; // 等价于 z = z * (2 + 3),结果是 25

5. 最佳实践建议

5.1 提高代码可读性

// 好的做法:清晰易懂
let counter = 0;
counter++;
counter += 5;

// 避免过于复杂的表达式
let result = ++a + b++ * c--; // 难以理解

5.2 注意类型转换

// 明确意图,避免隐式转换带来的困惑
let numStr = "10";
let result = +numStr + 5; // 明确转换为数字后相加,结果为 15

// 而不是
let result2 = numStr + 5; // 字符串连接,结果为 "105"

5.3 避免副作用

// 避免在一个表达式中多次使用 ++/-- 修改同一变量
let x = 1;
let y = x++ + x++; // 不推荐,行为难以预测

// 更清晰的写法
let y = x + (x + 1);
x += 2;