JavaScript && 和 || 运算符:解锁短路求值的秘密与实用技巧163
---
欢迎来到我的技术博客!今天我们要聊聊 JavaScript 中两个“老朋友”——逻辑与运算符 `&&` 和逻辑或运算符 `||`。你可能会觉得它们很简单,不就是用来做布尔判断的吗?其实不然,在 JavaScript 这门灵活的语言里,`&&` 和 `||` 远不止布尔运算那么简单,它们背后隐藏着“短路求值”的强大机制,能帮助我们写出更简洁、更高效、更具表现力的代码。
在正式深入 `&&` 和 `||` 之前,我们得先澄清一个常见的混淆点:你可能在标题中看到了 `&` 这个符号。在 JavaScript 中,`&` 和 `&&` 是完全不同的概念。
1. 辨析:& 和 && 的不同
1.1. `&` (位运算符:按位与)
`&` 是一个位运算符。它将操作数转换为32位整数(内部处理),然后对这两个数的每一位进行“与”操作。只有当对应的两个二进制位都为1时,结果位才为1。最终结果是一个数字。
(5 & 1); // 5的二进制是0101,1的二进制是0001
// 0101
// & 0001
// -------
// 0001 (结果是1)
(6 & 3); // 6的二进制是0110,3的二进制是0011
// 0110
// & 0011
// -------
// 0010 (结果是2)
位运算符在日常的前端开发中,除非涉及到某些底层优化、权限管理或特定算法,否则使用频率相对较低。
1.2. `&&` (逻辑运算符:逻辑与)
`&&` 是一个逻辑运算符,它用于布尔表达式的判断。但在 JavaScript 中,它不仅仅返回 `true` 或 `false`,它会返回其操作数之一。这就是我们今天讨论的重点!
2. 核心概念:JavaScript 中的“真值”与“假值”
要彻底理解 `&&` 和 `||` 的行为,我们必须先掌握 JavaScript 中的“真值”(truthy)和“假值”(falsy)概念。
在 JavaScript 中,以下六种值被认为是假值:
`false`
`0` (数字零)
`""` (空字符串)
`null`
`undefined`
`NaN` (Not-a-Number)
除了这六种值之外,其他所有值都被认为是真值。例如:`true`, `1`, `-1`, `"hello"`, `{}`, `[]`, `function(){}`, `Infinity` 等等。
当你把一个非布尔值放在一个需要布尔值的地方(比如 `if` 语句的条件表达式中),JavaScript 会自动将其转换为相应的布尔值(真值转为 `true`,假值转为 `false`)。
3. 逻辑与运算符 `&&`:短路求值与妙用
`&&` 运算符被称为“逻辑与”,它的核心规则是:
如果第一个操作数是假值,`&&` 会立即返回第一个操作数的值,不再计算第二个操作数。
如果第一个操作数是真值,`&&` 会继续计算第二个操作数,并返回第二个操作数的值。
这种特性被称为短路求值(Short-Circuit Evaluation)。
3.1. `&&` 的返回值
`&&` 不总是返回 `true` 或 `false`,它返回的是参与运算的某个操作数:
(true && 'Hello'); // 'Hello' (第一个是真,返回第二个)
(false && 'World'); // false (第一个是假,返回第一个)
(0 && 'JavaScript'); // 0 (第一个是假,返回第一个)
('JS' && 123); // 123 (第一个是真,返回第二个)
(null && undefined); // null (第一个是假,返回第一个)
('A' && 'B'); // 'B' (第一个是真,返回第二个)
3.2. `&&` 的实用场景
场景一:条件执行 (Conditional Execution)
这是 `&&` 最常见的非布尔用法。当你想在某个条件为真时才执行某个函数或代码块,可以这样写:
let userLoggedIn = true;
userLoggedIn && showUserProfile(); // 只有当userLoggedIn为真时,showUserProfile()才会被调用
function showUserProfile() {
("显示用户资料");
}
let isAdmin = false;
isAdmin && deleteUser(); // isAdmin为假,deleteUser()不会被调用
function deleteUser() {
("删除用户");
}
这比传统的 `if` 语句写起来更简洁:
`if (userLoggedIn) { showUserProfile(); }`
场景二:避免空引用错误 (Preventing Null/Undefined Errors)
在访问对象属性之前,确保对象本身存在,可以有效避免 `Cannot read property 'x' of undefined` 或 `null` 的错误。
const user = {
profile: {
name: "张三",
address: {
city: "北京"
}
}
};
const userName = user && && ;
(userName); // "张三"
const admin = null;
const adminName = admin && && ;
(adminName); // null (因为admin是假值,直接短路返回admin的值)
// 如果没有,userName也会是undefined
const user2 = {};
const userName2 = user2 && && ;
(userName2); // undefined (因为是undefined,是假值,直接返回)
这种链式判断在处理可能不存在的嵌套属性时非常有用。ES2020 引入的可选链操作符 `?.` (`user?.profile?.name`) 提供了更现代和优雅的解决方案,但 `&&` 的这种用法依然非常常见。
场景三:选择第一个假值或最后一个真值
当你有一系列值,并且想找到其中第一个假值,或者在所有值都是真值时取最后一个真值,`&&` 就能派上用场。
(1 && 2 && 3); // 3 (都是真值,返回最后一个真值)
(1 && 0 && 3); // 0 (第一个假值是0,返回0)
('A' && '' && 'C'); // '' (第一个假值是空字符串,返回空字符串)
4. 逻辑或运算符 `||`:短路求值与设置默认值
`||` 运算符被称为“逻辑或”,它的核心规则是:
如果第一个操作数是真值,`||` 会立即返回第一个操作数的值,不再计算第二个操作数。
如果第一个操作数是假值,`||` 会继续计算第二个操作数,并返回第二个操作数的值。
`||` 也同样具备短路求值的特性。
4.1. `||` 的返回值
`||` 同样不总是返回 `true` 或 `false`,它返回的是参与运算的某个操作数:
(true || 'Hello'); // true (第一个是真,返回第一个)
(false || 'World'); // 'World' (第一个是假,返回第二个)
(0 || 'JavaScript'); // 'JavaScript' (第一个是假,返回第二个)
('JS' || 123); // 'JS' (第一个是真,返回第一个)
(null || undefined); // undefined (第一个是假,返回第二个)
('A' || 'B'); // 'A' (第一个是真,返回第一个)
4.2. `||` 的实用场景
场景一:设置默认值 (Setting Default Values)
这是 `||` 最经典、最常见的用法。当一个变量可能为假值(如 `null`, `undefined`, `0`, `""`)时,你可以用 `||` 来为其提供一个默认值。
function greet(name) {
name = name || '访客'; // 如果name是假值,就使用'访客'作为默认值
(`你好,${name}!`);
}
greet('李四'); // 输出: 你好,李四!
greet(null); // 输出: 你好,访客!
greet(undefined); // 输出: 你好,访客!
greet(''); // 输出: 你好,访客!
greet(0); // 输出: 你好,访客! (注意:如果0是合法值,这可能不是你想要的)
场景二:选择第一个真值或最后一个假值
当你有一系列值,并且想找到其中第一个真值,或者在所有值都是假值时取最后一个假值,`||` 就能派上用场。
(0 || null || 'Hello' || 'World'); // 'Hello' (找到第一个真值)
(0 || '' || undefined); // undefined (都是假值,返回最后一个假值)
(false || true || 'Foo'); // true (找到第一个真值)
场景三:配置对象合并(简化版)
在简单的配置场景中,可以用来优先使用用户配置,如果用户没有提供,则使用默认配置。
const userSettings = {
theme: 'dark'
};
const defaultSettings = {
theme: 'light',
fontSize: 16
};
// 假设我们只关心theme
const finalTheme = || ;
(finalTheme); // 'dark'
const userSettings2 = {}; // 用户没有设置theme
const finalTheme2 = || ;
(finalTheme2); // 'light'
当然,对于复杂的配置对象合并,更推荐使用 `()` 或扩展运算符 `...`。
注意 `0` 和 `''` 作为有效值的问题:`??` 登场
上面提到,`greet(0)` 和 `greet('')` 都会输出“你好,访客!”。在某些业务场景中,`0` 和空字符串 `''` 是合法的有效值,不应该被视为“缺失”而替换为默认值。这时,ES2020 引入的空值合并操作符 `??` 就派上用场了。
`??` 只在左侧操作数为 `null` 或 `undefined` 时,才会返回右侧操作数。它不会将 `0` 或 `''` 视为缺失值。
function greetStrict(name) {
name = name ?? '访客'; // 只有当name是null或undefined时,才使用'访客'
(`你好,${name}!`);
}
greetStrict('李四'); // 输出: 你好,李四!
greetStrict(null); // 输出: 你好,访客!
greetStrict(undefined); // 输出: 你好,访客!
greetStrict(''); // 输出: 你好,! (空字符串被保留)
greetStrict(0); // 输出: 你好,0! (数字0被保留)
所以,在设置默认值时,要根据实际需求选择 `||` (针对所有假值) 还是 `??` (只针对 `null` 和 `undefined`)。
5. `&&` 和 `||` 的优先级
了解操作符优先级也很重要。在 JavaScript 中,`&&` 的优先级高于 `||`。
这意味着 `a || b && c` 会被解析为 `a || (b && c)`。
(true || false && false); // true || (false && false) => true || false => true
(false || true && false); // false || (true && false) => false || false => false
如果对优先级不确定,或者为了代码可读性,强烈建议使用括号来明确操作顺序。
6. 总结与建议
JavaScript 的 `&&` 和 `||` 运算符远比表面上看起来强大。它们利用“短路求值”和“真值/假值”的特性,能够帮助我们:
`&&` 用于:条件执行、安全访问嵌套属性、选择第一个假值或最后一个真值。
`||` 用于:设置默认值(应对所有假值)、选择第一个真值或最后一个假值。
掌握这些技巧,能够让你的代码更加简洁和富有表现力,减少 `if/else` 语句的嵌套,提高代码的可读性(在合理使用的情况下)。同时,也要注意 `0` 和 `''` 等特殊假值可能带来的问题,并适时考虑使用 `??` 操作符。
希望通过这篇文章,你对 `&&` 和 `||` 运算符有了更深入的理解!在日常开发中多加练习和运用,你就会发现它们是多么得心应手。如果你有任何疑问或想分享你的使用心得,欢迎在评论区留言!
2025-10-20

Perl FastCGI 全攻略:安装配置、性能优化与实战指南
https://jb123.cn/perl/70164.html

脚本语言学习全攻略:从零开始,书籍、网站与实战资源推荐
https://jb123.cn/jiaobenyuyan/70163.html

Python编程神器:IDE深度解析与选择指南
https://jb123.cn/python/70162.html

深度解析JavaScript中的换行与文本格式化:告别乱码与布局困扰
https://jb123.cn/javascript/70161.html

JavaScript中的Scheme基因:探寻Lisp血统与函数式编程的奥秘
https://jb123.cn/javascript/70160.html
热门文章

JavaScript (JS) 中的 JSF (JavaServer Faces)
https://jb123.cn/javascript/25790.html

JavaScript 枚举:全面指南
https://jb123.cn/javascript/24141.html

JavaScript 逻辑与:学习布尔表达式的基础
https://jb123.cn/javascript/20993.html

JavaScript 中保留小数的技巧
https://jb123.cn/javascript/18603.html

JavaScript 调试神器:步步掌握开发调试技巧
https://jb123.cn/javascript/4718.html