1. 操作符概述
操作符是JavaScript中用于执行特定运算的符号或关键字。它们是编程语言的基础构建块,用于操作数据、执行计算、比较值和控制程序流程。
操作符的分类
- 一元操作符:只需要一个操作数
- 二元操作符:需要两个操作数
- 三元操作符:需要三个操作数(只有条件操作符)
2. 算术操作符
算术操作符用于执行数学运算。
基本算术操作符
操作符 | 名称 | 示例 | 结果 |
---|---|---|---|
+ | 加法 | 5 + 3 | 8 |
- | 减法 | 5 - 3 | 2 |
* | 乘法 | 5 * 3 | 15 |
/ | 除法 | 6 / 3 | 2 |
% | 取余 | 7 % 3 | 1 |
** | 幂运算 | 2 ** 3 | 8 |
示例代码
// 基本算术运算
let a = 10;
let 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
// 注意:字符串的加法运算
console.log("Hello" + " World"); // "Hello World"
console.log("5" + 3); // "53" (字符串连接)
console.log(5 + "3"); // "53" (字符串连接)
3. 赋值操作符
赋值操作符用于给变量赋值。
基本赋值操作符
=
:基本赋值
复合赋值操作符
操作符 | 等价于 | 示例 | 结果 |
---|---|---|---|
+= | a = a + b | a += 3 | 将3加到a上 |
-= | a = a - b | a -= 3 | 从a中减去3 |
*= | a = a * b | a *= 3 | 将a乘以3 |
/= | a = a / b | a /= 3 | 将a除以3 |
%= | a = a % b | a %= 3 | a对3取余 |
**= | a = a ** b | a **= 3 | a的3次方 |
示例代码
let x = 10;
x += 5; // x = x + 5, 结果: 15
x -= 3; // x = x - 3, 结果: 12
x *= 2; // x = x * 2, 结果: 24
x /= 4; // x = x / 4, 结果: 6
x %= 4; // x = x % 4, 结果: 2
x **= 3; // x = x ** 3, 结果: 8
console.log(x); // 8
4. 自增/自减操作符
用于将数值增加或减少1。
前置和后置的区别
操作符 | 名称 | 说明 |
---|---|---|
++a | 前置自增 | 先增加,再返回值 |
a++ | 后置自增 | 先返回值,再增加 |
--a | 前置自减 | 先减少,再返回值 |
a-- | 后置自减 | 先返回值,再减少 |
示例代码
let a = 5;
let b = 5;
// 前置自增
console.log(++a); // 6 (先增加,再返回)
console.log(a); // 6
// 后置自增
console.log(b++); // 5 (先返回,再增加)
console.log(b); // 6
// 在表达式中的使用
let x = 10;
let y = ++x + x++;
// ++x: x变为11,返回11
// x++: 返回11,然后x变为12
// y = 11 + 11 = 22
console.log(y); // 22
console.log(x); // 12
5. 比较操作符
比较操作符用于比较两个值,返回布尔值。
相等性比较
操作符 | 名称 | 说明 |
---|---|---|
== | 相等 | 值相等(会进行类型转换) |
!= | 不等 | 值不等(会进行类型转换) |
=== | 严格相等 | 值和类型都相等 |
!== | 严格不等 | 值或类型不等 |
关系比较
操作符 | 名称 | 示例 |
---|---|---|
> | 大于 | 5 > 3 |
< | 小于 | 3 < 5 |
>= | 大于等于 | 5 >= 5 |
<= | 小于等于 | 3 <= 5 |
示例代码
// 相等性比较
console.log(5 == "5"); // true (类型转换)
console.log(5 === "5"); // false (严格比较)
console.log(5 != "5"); // false
console.log(5 !== "5"); // true
// 特殊值比较
console.log(null == undefined); // true
console.log(null === undefined); // false
// 关系比较
console.log(5 > 3); // true
console.log("abc" < "def"); // true (字符串比较)
// 注意:NaN的特殊性
console.log(NaN === NaN); // false
console.log(isNaN(NaN)); // true (正确检测NaN的方法)
6. 逻辑操作符
逻辑操作符用于布尔逻辑运算。
基本逻辑操作符
操作符 | 名称 | 说明 |
---|---|---|
&& | 逻辑与 | 所有操作数为真时返回真 |
| | 逻辑或 | 任一操作数为真时返回真 |
! | 逻辑非 | 对操作数取反 |
短路求值
&&
:如果第一个操作数为假,不会评估第二个操作数||
:如果第一个操作数为真,不会评估第二个操作数
示例代码
// 基本逻辑运算
console.log(true && true); // true
console.log(true && false); // false
console.log(false || true); // true
console.log(!true); // false
// 短路求值
let x = 5;
let y = 0;
// && 短路求值
console.log(x > 0 && ++y); // true, y变为1
console.log(x < 0 && ++y); // false, y不会增加
// || 短路求值
let name = "";
let defaultName = "Guest";
let displayName = name || defaultName; // "Guest"
// 实用模式
function greet(name) {
name = name || "Guest"; // 默认值模式
console.log("Hello, " + name);
}
// 用于条件执行
let isLoggedIn = true;
isLoggedIn && console.log("Welcome back!"); // 只有登录时才执行
7. 位操作符
位操作符直接操作数字的二进制表示。
位操作符列表
操作符 | 名称 | 示例 | 说明 |
---|---|---|---|
& | 按位与 | 5 & 3 | 对应位都为1则为1 |
| | 按位或 | 5 | 3 | 对应位有1则为1 |
^ | 按位异或 | 5 ^ 3 | 对应位不同则为1 |
~ | 按位取反 | ~5 | 所有位取反 |
<< | 左移 | 5 << 1 | 向左移动指定位数 |
>> | 右移 | 5 >> 1 | 向右移动指定位数 |
>>> | 无符号右移 | 5 >>> 1 | 无符号向右移动 |
示例代码
// 位运算示例
console.log(5 & 3); // 1 (101 & 011 = 001)
console.log(5 | 3); // 7 (101 | 011 = 111)
console.log(5 ^ 3); // 6 (101 ^ 011 = 110)
console.log(~5); // -6 (按位取反)
// 位移运算
console.log(5 << 1); // 10 (左移1位,相当于乘以2)
console.log(5 >> 1); // 2 (右移1位,相当于除以2)
// 实用技巧
// 检查奇偶数
function isOdd(num) {
return (num & 1) === 1;
}
// 快速乘除2的幂
let num = 16;
console.log(num << 2); // 64 (乘以4)
console.log(num >> 2); // 4 (除以4)
8. 条件操作符(三元操作符)
条件操作符是JavaScript中唯一的三元操作符。
语法
condition ? value1 : value2
示例代码
// 基本用法
let age = 18;
let status = age >= 18 ? "成年" : "未成年";
console.log(status); // "成年"
// 嵌套三元操作符
let score = 85;
let grade = score >= 90 ? "A" :
score >= 80 ? "B" :
score >= 70 ? "C" :
score >= 60 ? "D" : "F";
console.log(grade); // "B"
// 在函数中使用
function max(a, b) {
return a > b ? a : b;
}
// 用于默认值(ES6之前的方法)
function greet(name) {
name = name ? name : "Guest";
console.log("Hello, " + name);
}
9. typeof操作符
typeof
操作符返回一个字符串,表示操作数的数据类型。
返回值列表
数据类型 | typeof返回值 |
---|---|
undefined | ”undefined” |
Boolean | ”boolean” |
Number | ”number” |
String | ”string” |
Function | ”function” |
Object | ”object” |
Symbol | ”symbol” |
BigInt | ”bigint” |
示例代码
// 基本类型检测
console.log(typeof undefined); // "undefined"
console.log(typeof true); // "boolean"
console.log(typeof 123); // "number"
console.log(typeof "hello"); // "string"
console.log(typeof Symbol()); // "symbol"
// 特殊情况
console.log(typeof null); // "object" (历史遗留问题)
console.log(typeof [1, 2, 3]); // "object"
console.log(typeof {}); // "object"
console.log(typeof function(){}); // "function"
// 实用函数
function getType(value) {
if (value === null) return "null";
if (Array.isArray(value)) return "array";
return typeof value;
}
console.log(getType(null)); // "null"
console.log(getType([1, 2])); // "array"
console.log(getType({})); // "object"
10. in操作符
in
操作符用于检查对象是否具有指定的属性。
语法
property in object
示例代码
// 对象属性检查
let person = {
name: "John",
age: 30
};
console.log("name" in person); // true
console.log("height" in person); // false
console.log("toString" in person); // true (继承的属性)
// 数组索引检查
let arr = ["a", "b", "c"];
console.log(0 in arr); // true
console.log(3 in arr); // false
// 与hasOwnProperty的区别
console.log(person.hasOwnProperty("name")); // true
console.log(person.hasOwnProperty("toString")); // false
console.log("toString" in person); // true
// 用于检查方法是否存在
if ("push" in Array.prototype) {
console.log("数组支持push方法");
}
11. instanceof操作符
instanceof
操作符用于检测构造函数的prototype属性是否出现在对象的原型链中。
语法
object instanceof constructor
示例代码
// 基本类型检测
let arr = [1, 2, 3];
let obj = {};
let date = new Date();
console.log(arr instanceof Array); // true
console.log(arr instanceof Object); // true (Array继承自Object)
console.log(obj instanceof Object); // true
console.log(date instanceof Date); // true
console.log(date instanceof Object); // true
// 自定义构造函数
function Person(name) {
this.name = name;
}
let john = new Person("John");
console.log(john instanceof Person); // true
console.log(john instanceof Object); // true
// 注意:原始类型
console.log("hello" instanceof String); // false
console.log(123 instanceof Number); // false
// 但是包装对象会返回true
console.log(new String("hello") instanceof String); // true
console.log(new Number(123) instanceof Number); // true
// 用于类型检查函数
function isArray(value) {
return value instanceof Array;
}
// ES6替代方案
console.log(Array.isArray(arr)); // true (推荐使用)
12. 解构赋值操作符
ES6引入的解构赋值允许从数组或对象中提取值。
数组解构
// 基本数组解构
let [a, b, c] = [1, 2, 3];
console.log(a, b, c); // 1 2 3
// 跳过元素
let [first, , third] = [1, 2, 3];
console.log(first, third); // 1 3
// 默认值
let [x = 10, y = 20] = [1];
console.log(x, y); // 1 20
// 剩余元素
let [head, ...tail] = [1, 2, 3, 4];
console.log(head); // 1
console.log(tail); // [2, 3, 4]
// 交换变量
let p = 1, q = 2;
[p, q] = [q, p];
console.log(p, q); // 2 1
对象解构
// 基本对象解构
let {name, age} = {name: "John", age: 30, city: "New York"};
console.log(name, age); // "John" 30
// 重命名
let {name: userName, age: userAge} = {name: "John", age: 30};
console.log(userName, userAge); // "John" 30
// 默认值
let {x = 10, y = 20} = {x: 1};
console.log(x, y); // 1 20
// 嵌套解构
let user = {
id: 1,
profile: {
name: "John",
email: "john@example.com"
}
};
let {profile: {name: userName2, email}} = user;
console.log(userName2, email); // "John" "john@example.com"
// 函数参数解构
function greet({name, age = 25}) {
console.log(`Hello ${name}, you are ${age} years old`);
}
greet({name: "Alice", age: 30}); // "Hello Alice, you are 30 years old"
13. 展开操作符
ES6的展开操作符(…)可以展开可迭代对象。
示例代码
// 数组展开
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4, 5, 6]
// 复制数组
let original = [1, 2, 3];
let copy = [...original];
copy.push(4);
console.log(original); // [1, 2, 3]
console.log(copy); // [1, 2, 3, 4]
// 对象展开
let obj1 = {a: 1, b: 2};
let obj2 = {c: 3, d: 4};
let merged = {...obj1, ...obj2};
console.log(merged); // {a: 1, b: 2, c: 3, d: 4}
// 函数调用
function sum(a, b, c) {
return a + b + c;
}
let numbers = [1, 2, 3];
console.log(sum(...numbers)); // 6
// 字符串展开
let str = "hello";
let chars = [...str];
console.log(chars); // ["h", "e", "l", "l", "o"]
14. 操作符优先级
了解操作符优先级有助于理解复杂表达式的求值顺序。
优先级表(从高到低)
优先级 | 操作符 | 说明 |
---|---|---|
20 | () | 分组 |
19 | . [] | 成员访问 |
18 | new | 构造函数调用 |
17 | () | 函数调用 |
16 | ++ -- | 后置递增递减 |
15 | ! ~ + - ++ -- | 一元操作符 |
14 | ** | 幂运算 |
13 | * / % | 乘法类 |
12 | + - | 加法类 |
11 | << >> >>> | 位移 |
10 | < <= > >= | 关系比较 |
9 | == != === !== | 相等比较 |
8-4 | & ^ | | 位运算 |
3 | && | 逻辑与 |
2 | | | 逻辑或 |
1 | ?: | 条件操作符 |
0 | = += -= 等 | 赋值 |
示例代码
// 优先级示例
let result1 = 2 + 3 * 4; // 14 (先乘法,后加法)
let result2 = (2 + 3) * 4; // 20 (括号优先)
// 复杂表达式
let a = 5;
let b = 3;
let c = 2;
let result = a + b * c > 10 && a < b || c == 2;
// 求值顺序:
// 1. b * c = 6
// 2. a + 6 = 11
// 3. 11 > 10 = true
// 4. a < b = false
// 5. true && false = false
// 6. c == 2 = true
// 7. false || true = true
console.log(result); // true
// 建议:使用括号明确意图
let clearResult = (a + (b * c) > 10) && (a < b) || (c == 2);
15. 常见陷阱和最佳实践
常见陷阱
- 类型转换陷阱
// 避免使用 == ,推荐使用 ===
console.log(0 == false); // true
console.log("" == false); // true
console.log(null == undefined); // true
// 推荐做法
console.log(0 === false); // false
console.log("" === false); // false
console.log(null === undefined); // false
- 浮点数运算
// 浮点数精度问题
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3); // false
// 解决方案
console.log(Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON); // true
- 自增操作符陷阱
let i = 1;
let arr = [i++, ++i, i++];
console.log(arr); // [1, 3, 3]
console.log(i); // 4
最佳实践
- 使用严格比较
// 好的做法
if (value === null) { /* ... */ }
if (typeof value === "string") { /* ... */ }
// 避免
if (value == null) { /* ... */ }
- 合理使用逻辑操作符
// 使用 || 提供默认值
function greet(name) {
name = name || "Guest";
console.log("Hello, " + name);
}
// ES6+ 使用默认参数(更好)
function greetES6(name = "Guest") {
console.log("Hello, " + name);
}
- 避免过度使用三元操作符
// 可以接受
let message = isLoggedIn ? "Welcome" : "Please login";
// 过于复杂,建议使用 if-else
let status = score >= 90 ? "A" :
score >= 80 ? "B" :
score >= 70 ? "C" : "F";
// 更好的做法
function getGrade(score) {
if (score >= 90) return "A";
if (score >= 80) return "B";
if (score >= 70) return "C";
return "F";
}
总结
JavaScript操作符是编程的基础工具,掌握它们的用法和特性对编写高质量的代码至关重要。记住以下要点:
- 类型安全:优先使用严格比较(=、!)
- 可读性:使用括号明确运算优先级
- 性能:理解短路求值的特性
- 现代化:善用ES6+的新特性(解构、展开操作符)
- 避免陷阱:注意类型转换和浮点数运算的问题