运算符概述
运算符用于对值执行操作。JavaScript支持多种类型的运算符:
- 算术运算符 - 执行数学运算
- 赋值运算符 - 为变量赋值
- 比较运算符 - 比较值的大小
- 逻辑运算符 - 组合布尔值
- 位运算符 - 操作二进制位
- 字符串运算符 - 连接字符串
- 条件运算符 - 基于条件选择值
- 类型运算符 - 检查变量类型
- 其他运算符 - 逗号、delete、void等
运算符分类
根据操作数的数量,运算符可以分为:
- 一元运算符 - 操作一个操作数,如:
++,--,!,typeof - 二元运算符 - 操作两个操作数,如:
+,-,*,/,&& - 三元运算符 - 操作三个操作数,如:
? :
算术运算符
用于执行基本的数学运算:
| 运算符 | 描述 | 示例 | 结果 |
|---|---|---|---|
+ |
加法 | 5 + 3 |
8 |
- |
减法 | 5 - 3 |
2 |
* |
乘法 | 5 * 3 |
15 |
/ |
除法 | 15 / 3 |
5 |
% |
取模(余数) | 10 % 3 |
1 |
** |
指数(ES2016) | 2 ** 3 |
8 |
++ |
递增 | x++ |
x + 1 |
-- |
递减 | x-- |
x - 1 |
+ (一元) |
一元加 | +"5" |
5 |
- (一元) |
一元减 | -5 |
-5 |
算术运算符示例
let a = 10, b = 3;
console.log(a + b); // 13
console.log(a - b); // 7
console.log(a * b); // 30
console.log(a / b); // 3.333...
console.log(a % b); // 1
console.log(a ** b); // 1000
// 递增和递减
let x = 5;
console.log(x++); // 5 (后置递增)
console.log(x); // 6
console.log(++x); // 7 (前置递增)
// 一元加减运算符
console.log(+"5"); // 5 (字符串转数字)
console.log(-"5"); // -5
console.log(+true); // 1
console.log(+false); // 0
注意: 递增和递减运算符有前置和后置之分。前置运算符先进行运算再返回值,后置运算符先返回值再进行运算。
赋值运算符
用于为变量赋值:
| 运算符 | 示例 | 等价于 |
|---|---|---|
= |
x = y |
x = y |
+= |
x += y |
x = x + y |
-= |
x -= y |
x = x - y |
*= |
x *= y |
x = x * y |
/= |
x /= y |
x = x / y |
%= |
x %= y |
x = x % y |
**= |
x **= y |
x = x ** y |
&= |
x &= y |
x = x & y |
|= |
x |= y |
x = x | y |
^= |
x ^= y |
x = x ^ y |
<<= |
x <<= y |
x = x << y |
>>= |
x >>= y |
x = x >> y |
>>>= |
x >>>= y |
x = x >>> y |
赋值运算符示例
let x = 10;
x += 5; // x = 15
x -= 3; // x = 12
x *= 2; // x = 24
x /= 4; // x = 6
x %= 4; // x = 2
x **= 3; // x = 8
// 字符串连接
let str = "Hello";
str += " World"; // "Hello World"
// 解构赋值 (ES6)
let [a, b] = [1, 2]; // a = 1, b = 2
let {name, age} = {name: "John", age: 30}; // name = "John", age = 30
比较运算符
用于比较值,返回布尔值:
| 运算符 | 描述 | 示例 | 结果 |
|---|---|---|---|
== |
等于(宽松) | 5 == "5" |
true |
=== |
等于(严格) | 5 === "5" |
false |
!= |
不等于(宽松) | 5 != "6" |
true |
!== |
不等于(严格) | 5 !== "5" |
true |
> |
大于 | 5 > 3 |
true |
< |
小于 | 5 < 3 |
false |
>= |
大于等于 | 5 >= 5 |
true |
<= |
小于等于 | 5 <= 3 |
false |
比较运算符示例
console.log(5 == "5"); // true (类型转换)
console.log(5 === "5"); // false (类型不同)
console.log(5 != "6"); // true
console.log(5 !== "5"); // true
console.log(10 > 5); // true
console.log(10 < 5); // false
console.log(10 >= 10); // true
console.log(10 <= 5); // false
// 特殊比较
console.log(null == undefined); // true
console.log(null === undefined); // false
console.log(NaN == NaN); // false (特殊规则)
console.log(NaN === NaN); // false
console.log(0 == false); // true
console.log("" == false); // true
console.log("0" == false); // true
最佳实践: 总是使用严格相等(===)和严格不相等(!==)运算符,避免类型转换带来的意外行为。
对象比较的特殊情况
对象比较
// 对象比较的是引用,而不是内容
let obj1 = { value: 10 };
let obj2 = { value: 10 };
let obj3 = obj1;
console.log(obj1 == obj2); // false (不同对象)
console.log(obj1 === obj2); // false (不同对象)
console.log(obj1 == obj3); // true (相同引用)
console.log(obj1 === obj3); // true (相同引用)
逻辑运算符
用于组合或反转布尔值:
| 运算符 | 描述 | 示例 | 结果 |
|---|---|---|---|
&& |
逻辑与 | true && false |
false |
|| |
逻辑或 | true || false |
true |
! |
逻辑非 | !true |
false |
?? (ES2020) |
空值合并 | null ?? "默认" |
"默认" |
逻辑运算符示例
// 基本逻辑运算
console.log(true && true); // true
console.log(true && false); // false
console.log(true || false); // true
console.log(false || false); // false
console.log(!true); // false
console.log(!false); // true
// 短路求值
let result1 = true && "Hello"; // "Hello"
let result2 = false && "Hello"; // false
let result3 = true || "Hello"; // true
let result4 = false || "Hello"; // "Hello"
// 复杂逻辑表达式
let age = 25;
let hasLicense = true;
let canDrive = age >= 18 && hasLicense; // true
// 空值合并运算符 (??)
let value1 = null ?? "默认值"; // "默认值"
let value2 = undefined ?? "默认值"; // "默认值"
let value3 = 0 ?? "默认值"; // 0
let value4 = "" ?? "默认值"; // ""
注意: 空值合并运算符 (??) 与逻辑或 (||) 的区别在于,?? 只在值为 null 或 undefined 时使用默认值,而 || 会在任何假值(0, "",
false 等)时使用默认值。
位运算符
位运算符对操作数的二进制表示进行操作:
| 运算符 | 描述 | 示例 | 结果 |
|---|---|---|---|
& |
按位与 | 5 & 1 |
1 |
| |
按位或 | 5 | 1 |
5 |
^ |
按位异或 | 5 ^ 1 |
4 |
~ |
按位非 | ~5 |
-6 |
<< |
左移 | 5 << 1 |
10 |
>> |
右移 | 5 >> 1 |
2 |
>>> |
无符号右移 | -5 >>> 1 |
2147483645 |
位运算符示例
// 按位与
console.log(5 & 1); // 1 (0101 & 0001 = 0001)
// 按位或
console.log(5 | 1); // 5 (0101 | 0001 = 0101)
// 按位异或
console.log(5 ^ 1); // 4 (0101 ^ 0001 = 0100)
// 按位非
console.log(~5); // -6 (~00000000000000000000000000000101 = 11111111111111111111111111111010)
// 左移
console.log(5 << 1); // 10 (0101 << 1 = 1010)
// 右移
console.log(5 >> 1); // 2 (0101 >> 1 = 0010)
// 无符号右移
console.log(-5 >>> 1); // 2147483645
其他运算符
条件(三元)运算符
三元运算符
// 语法: condition ? expr1 : expr2
let age = 20;
let status = age >= 18 ? "成年人" : "未成年人";
console.log(status); // "成年人"
// 嵌套三元运算符
let score = 85;
let grade = score >= 90 ? "A" :
score >= 80 ? "B" :
score >= 70 ? "C" : "D";
console.log(grade); // "B"
// 与逻辑运算符结合使用
let name = null;
let displayName = name ? name : "匿名用户";
// 等价于: let displayName = name || "匿名用户";
类型运算符
类型运算符
console.log(typeof "hello"); // "string"
console.log(typeof 42); // "number"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (历史遗留问题)
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof function(){}); // "function"
let arr = [1, 2, 3];
console.log(Array.isArray(arr)); // true
console.log(arr instanceof Array); // true
function Person() {}
let person = new Person();
console.log(person instanceof Person); // true
其他特殊运算符
其他运算符
// 逗号运算符 - 从左到右求值,返回最后一个值
let x = (1, 2, 3); // x = 3
// void 运算符 - 计算表达式并返回 undefined
let result = void 5; // result = undefined
// delete 运算符 - 删除对象属性
let obj = { a: 1, b: 2 };
delete obj.a;
console.log(obj); // { b: 2 }
// in 运算符 - 检查属性是否存在
console.log("b" in obj); // true
console.log("a" in obj); // false
运算符优先级
运算符按照优先级顺序执行:
| 优先级 | 运算符 | 描述 | 结合性 |
|---|---|---|---|
| 21 | () |
分组 | 不适用 |
| 20 | . [] new () |
成员访问、计算成员访问、new(带参数列表) | 从左到右 |
| 19 | () |
函数调用 | 从左到右 |
| 18 | new |
new(无参数列表) | 从右到左 |
| 17 | ++ -- |
后置递增、后置递减 | 不适用 |
| 16 | ! ~ +(一元) -(一元) ++
-- typeof void delete |
逻辑非、按位非、一元加减、前置递增递减、typeof、void、delete | 从右到左 |
| 15 | ** |
指数 | 从右到左 |
| 14 | * / % |
乘法、除法、取模 | 从左到右 |
| 13 | + - |
加法、减法 | 从左到右 |
| 12 | << >> >>> |
位移 | 从左到右 |
| 11 | < <= > >=
in instanceof |
关系、in、instanceof | 从左到右 |
| 10 | == != === !== |
相等性 | 从左到右 |
| 9 | & |
按位与 | 从左到右 |
| 8 | ^ |
按位异或 | 从左到右 |
| 7 | | |
按位或 | 从左到右 |
| 6 | && |
逻辑与 | 从左到右 |
| 5 | || ?? |
逻辑或、空值合并 | 从左到右 |
| 4 | ? : |
条件运算符 | 从右到左 |
| 3 | = += -= 等 |
赋值 | 从右到左 |
| 2 | yield yield* |
yield | 从右到左 |
| 1 | , |
逗号 | 从左到右 |
优先级示例
// 乘法优先于加法
let result1 = 2 + 3 * 4; // 14 (不是20)
// 使用括号改变优先级
let result2 = (2 + 3) * 4; // 20
// 逻辑运算符优先级: ! > && > ||
let a = true, b = false, c = true;
let result3 = a || b && c; // true (相当于 a || (b && c))
let result4 = (a || b) && c; // true
// 指数运算符是右结合的
let result5 = 2 ** 3 ** 2; // 512 (相当于 2 ** (3 ** 2))
let result6 = (2 ** 3) ** 2; // 64
建议: 当表达式复杂时,使用括号明确优先级,提高代码可读性。
实践练习
👆 请点击上方按钮进行演示操作
选择不同的演示按钮来探索JavaScript的各种功能和用法
练习代码
// 练习1: 复合运算
let x = 10, y = 3;
let result = (x + y) * (x - y) / y;
console.log(result); // 30.333...
// 练习2: 逻辑判断
let age = 25;
let hasID = true;
let hasTicket = false;
let canEnter = (age >= 18 && hasID) || hasTicket;
console.log(canEnter); // true
// 练习3: 三元运算符
let temperature = 22;
let clothing = temperature > 20 ? "T恤" : "外套";
console.log(clothing); // "T恤"
// 练习4: 位运算应用
let num = 13; // 二进制: 1101
let isEven = (num & 1) === 0; // 检查是否为偶数
console.log(isEven); // false
// 练习5: 运算符优先级理解
let a = 5, b = 3, c = 2;
let complexResult = a + b * c ** 2 / (a - b);
console.log(complexResult); // 14
常见问题与解答
1. 为什么应该使用 === 而不是 ==?
严格相等运算符 (===) 不会进行类型转换,行为更可预测。宽松相等运算符 (==) 会进行类型转换,可能导致意外的结果,例如:
== 的意外行为
console.log(0 == false); // true
console.log("" == false); // true
console.log(null == undefined); // true
2. 递增/递减运算符的前置和后置有什么区别?
前置运算符先进行运算再返回值,后置运算符先返回值再进行运算:
前置 vs 后置
let a = 5;
console.log(a++); // 5 (先返回值,再递增)
console.log(a); // 6
let b = 5;
console.log(++b); // 6 (先递增,再返回值)
console.log(b); // 6
3. 什么时候使用位运算符?
位运算符主要用于:
- 性能优化(某些位运算比算术运算更快)
- 处理二进制数据
- 实现特定的算法(如哈希函数、加密算法)
- 标志位操作
最佳实践
- 使用严格相等运算符 (=== 和 !==) 避免类型转换问题
- 在复杂表达式中使用括号明确优先级
- 避免使用位运算符处理非整数,因为会先转换为32位整数
- 谨慎使用递增/递减运算符,注意前置和后置的区别
- 使用空值合并运算符 (??) 代替逻辑或 (||) 设置默认值,避免0和""被当作假值
- 避免使用eval()函数,它存在安全风险