第4章:表达式和运算符(Expressions and Operators)
一、导读
1.1 本章学习目标
第4章讲解JavaScript的表达式和运算符。本章核心目标:
- 掌握各种运算符:算术、比较、逻辑、赋值运算符
- 理解短路求值:
&&和||的特殊行为 - 学会使用可选链和空值合并:ES2020的新特性
- 掌握运算符优先级:复杂表达式如何求值
- 理解三元运算符:条件表达式的简写
1.2 为什么本章如此重要
运算符是构建表达式的基础。JavaScript的运算符有一些独特的行为(如 + 既做加法又做字符串拼接),理解这些规则才能避免bug。可选链(?.)和空值合并(??)是现代JavaScript的重要特性,大大简化了代码。
1.3 核心问题引导
为什么 + 运算符有时做加法有时做字符串拼接?
?. 可选链解决了什么问题?
?? 和 || 有什么区别?
JavaScript的运算符优先级和C/Java有什么不同?
二、核心概念详解
4.1 算术运算符
javascript
console.log(10 + 3); // 13
console.log(10 - 3); // 7
console.log(10 * 3); // 30
console.log(10 / 3); // 3.333...
console.log(10 % 3); // 1(取余)
console.log(2 ** 10); // 1024(幂运算,ES2016)
// + 运算符的双重行为
console.log(5 + 3); // 8(数字加法)
console.log("5" + 3); // "53"(字符串拼接)
console.log(5 + "3"); // "53"
console.log("5" + "3"); // "53"
// 其他运算符触发数字转换
console.log("5" - 3); // 2
console.log("5" * "2"); // 10
console.log("5" / "2"); // 2.54.2 比较运算符
javascript
// 宽松相等(==):会类型转换
console.log(5 == "5"); // true
console.log(0 == false); // true
console.log(null == undefined); // true
console.log("" == 0); // true
// 严格相等(===):不转换
console.log(5 === "5"); // false
console.log(0 === false); // false
console.log(null === undefined); // false
// 推荐:始终使用 ===
// NaN的特殊性
console.log(NaN === NaN); // false
console.log(Object.is(NaN, NaN)); // true
// 对象比较(引用比较)
let a = [1, 2];
let b = [1, 2];
console.log(a === b); // false(不同引用)
console.log(a == b); // false4.3 逻辑运算符
javascript
// && 和 || 返回操作数的值(不只是true/false)
console.log(0 || "hello"); // "hello"
console.log("" || "default"); // "default"
console.log(null || 42); // 42
console.log(1 && "hello"); // "hello"
console.log(0 && "hello"); // 0
// 短路求值
let user = null;
let name = user && user.name; // null(不会报错)
// ! 取反
console.log(!true); // false
console.log(!0); // true
console.log(!""); // true
console.log(!null); // true
// 双重取反:转为布尔值
console.log(!!0); // false
console.log(!!"hello"); // true
console.log(!!null); // false4.4 可选链和空值合并
javascript
// 可选链(?.)ES2020
let user = {
name: "Alice",
address: {
city: "Beijing"
}
};
console.log(user.address?.city); // "Beijing"
console.log(user.phone?.number); // undefined(不会报错)
console.log(user.address?.zip?.code); // undefined
// 可选链用于函数调用
let obj = {
greet: function() { return "Hello"; }
};
console.log(obj.greet?.()); // "Hello"
console.log(obj.farewell?.()); // undefined
// 可选链用于数组
let arr = [1, 2, 3];
console.log(arr?.[0]); // 1
console.log(arr?.[10]); // undefined
// 空值合并(??)ES2020
// 只在左侧为null或undefined时返回右侧值
let value1 = null ?? "default";
console.log(value1); // "default"
let value2 = 0 ?? "default";
console.log(value2); // 0(0不是null/undefined)
let value3 = "" ?? "default";
console.log(value3); // ""(空字符串不是null/undefined)
// 对比 ||
console.log(0 || "default"); // "default"(0是falsy)
console.log(0 ?? "default"); // 0(0不是null/undefined)4.5 三元运算符
javascript
let age = 20;
let status = age >= 18 ? "adult" : "minor";
console.log(status); // "adult"
// 嵌套三元(不推荐,可读性差)
let score = 85;
let grade = score >= 90 ? "A" :
score >= 80 ? "B" :
score >= 70 ? "C" : "D";
console.log(grade); // "B"
// 在JSX中使用
// <div>{isLoggedIn ? <Dashboard /> : <Login />}</div>4.6 赋值运算符
javascript
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
// 逻辑赋值(ES2021)
let a = null;
a ||= "default"; // a = a || "default"
console.log(a); // "default"
let b = 0;
b ??= 42; // b = b ?? 42
console.log(b); // 42
let c = 1;
c &&= 2; // c = c && 2
console.log(c); // 24.7 运算符优先级
javascript
// 常见优先级(从高到低)
// 1. () 括号
// 2. ** 幂
// 3. * / % 乘除余
// 4. + - 加减
// 5. < > <= >= 比较
// 6. === !== 相等
// 7. && 逻辑与
// 8. || 逻辑或
// 9. ?? 空值合并
// 10. = += -= 赋值
let result = 2 + 3 * 4; // 14
let result2 = (2 + 3) * 4; // 20
let result3 = 2 ** 3 ** 2; // 512(右结合:2^(3^2))
// 逗号运算符
let val = (1, 2, 3); // val = 3
console.log(val);三、实战案例
4.1 安全访问深层对象
javascript
// 不使用可选链(繁琐)
let city1;
if (user && user.address && user.address.city) {
city1 = user.address.city;
}
// 使用可选链(简洁)
let city2 = user?.address?.city;
// 提供默认值
let city3 = user?.address?.city ?? "Unknown";4.2 条件渲染
javascript
// 根据条件选择不同值
function getDiscount(isMember, purchaseAmount) {
return isMember
? (purchaseAmount > 100 ? 0.2 : 0.1)
: (purchaseAmount > 100 ? 0.05 : 0);
}
console.log(getDiscount(true, 150)); // 0.2
console.log(getDiscount(false, 50)); // 0四、本章小结
第4章讲解了JavaScript的表达式和运算符:
算术运算符:+ 既做加法又做字符串拼接,注意类型转换。
比较运算符:推荐使用 ===,避免 == 的类型转换陷阱。
逻辑运算符:&& 和 || 返回操作数的值,支持短路求值。
可选链(?.):安全访问可能不存在的属性。
空值合并(??):只在null/undefined时提供默认值。
运算符优先级:使用括号明确意图。
五、思考与练习
思考题
为什么 + 运算符有双重行为?这是设计缺陷还是有意为之?
?? 和 || 在什么场景下行为不同?
可选链可以用于哪些场景?
为什么 NaN === NaN 返回 false?
编程练习
使用可选链和空值合并重写一段嵌套的if-else代码。
编写一个函数,安全地访问任意深度的对象属性。
实现一个简单的表达式计算器。