- 教程
【免费下载链接】jstips
This is about useful JS tips!
短路求值(Short-Circuit Evaluation)是 JavaScript 中&&与||两个逻辑运算符最实用的行为特性:表达式的结果一旦能被第一个操作数确定,第二个操作数就完全不会被执行。本指南以 jstips 第 27 期(_posts/en/javascript/2016-01-27-short-circuit-evaluation-in-js.md)为骨架,结合仓库内多个相关 tip,系统讲解如何用&&替代if、用||设置默认值、安全访问可能为undefined的对象属性,并深入 truthy/falsy、回调守卫与函数式循环等进阶场景。读完你将掌握一套可立即上手的简洁条件表达式写法,并理解其底层求值规则与边界陷阱。
一、什么是短路求值
短路求值的核心规则只有一条:只有当第一个操作数的值不足以决定整个逻辑表达式的结果时,第二个操作数才会被求值(执行)。具体到两个运算符:
- 对于逻辑与
&&:如果第一个操作数求值为false,那么无论第二个操作数是什么,整个表达式的结果都必然是false,因此第二个操作数不会被求值; - 对于逻辑或
||:如果第一个操作数求值为true,那么整个表达式的结果都必然是true,因此第二个操作数不会被求值。
反过来理解:a && b只有a为真时才需要看b;a || b只有a为假时才需要看b。这正是原文档(_posts/en/javascript/2016-01-27-short-circuit-evaluation-in-js.md)第一段所阐述的定义,也是下面所有实战技巧的理论基础。
二、用&&替代if语句
先定义一组测试条件与两个输出函数(与原文档示例一致):
var test = true; var isTrue = function(){ console.log('Test is true.'); }; var isFalse = function(){ console.log('Test is false.'); };传统写法需要一个完整的if语句:
// 普通的 if 语句 if(test){ isTrue(); // Test is true }利用&&的短路特性,当test为true时右侧的isTrue()才会执行,上面的语句可以压缩成一行:
// 上面的语句可以使用 '&&' 写为: ( test && isTrue() ); // Test is true当test为false时,&&左侧已经决定了整个表达式的结果为false,右侧函数根本不会被调用——这正是我们想要的"条件为真才执行"语义。仓库第 60 期 tip Three useful hacks 中同样收录了这个模式:
if(condition){ dosomething(); } // 等价于 condition && dosomething();可见这并非孤例,而是社区反复验证的通用写法。
三、用||替代if(!test)语句
把test置为false,传统写法是取反后判断:
test = false; if(!test){ isFalse(); // Test is false. }利用||的短路特性:当test为false时,左侧已无法确定结果,右侧isFalse()才会执行;当test为true时右侧被跳过。于是等价于一行:
( test || isFalse()); // Test is false.两种写法输出完全一致,但后者在表达"条件为假才执行"的意图时更加紧凑。&&管"为真时做",||管"为假时做",两者互补。
四、用||为函数参数设置默认值
||最经典的应用场景是给缺失的参数填充默认值:
function theSameOldFoo(name){ name = name || 'Bar' ; console.log("My best friend's name is " + name); } theSameOldFoo(); // My best friend's name is Bar theSameOldFoo('Bhaskar'); // My best friend's name is Bhaskar调用时不传参数,name为undefined(假值),||触发右侧求值,name被赋为默认值'Bar';传入'Bhaskar'时左侧为真值,直接短路保留原值。
仓库第 60 期 tip 对"变量默认值"的扩展演示更进一步:
var a; console.log(a); //undefined a = a || 'default value'; console.log(a); //default value a = a || 'new value'; console.log(a); //default value注意最后一步:a已经是'default value'(真值),a || 'new value'左侧短路,a保持原值不变——说明||默认值写法只会在左侧为假值时生效,一旦赋值成功就不会被再次覆盖。
五、用&&安全访问属性,避免报错
访问未定义对象的属性会抛出运行时错误,&&可以充当安全的"守卫":
var dog = { bark: function(){ console.log('Woof Woof'); } }; // 调用 dog.bark(); dog.bark(); // Woof Woof. // 但是当 dog 未定义时,dog.bark() 将会抛出 "Cannot read property 'bark' of undefined." 错误 // 防止这种情况,我们可以使用 &&。 dog && dog.bark(); // 只有当 dog 被定义时才会调用 dog.bark()原理依然来自短路规则:dog为undefined(假值)时,&&左侧已决定结果为假,右侧dog.bark()根本不会执行,从而避免Cannot read property 'bark' of undefined异常;dog存在时右侧正常调用。
六、深入一:truthy/falsy 是短路求值的判定基础
理解短路求值,必须先理解 JavaScript 的布尔化规则。仓库第 30 期 tip Converting truthy/falsy values to boolean 给出了完整的假值清单与真值示例:
!!"" // false !!0 // false !!null // false !!undefined // false !!NaN // false !!"hello" // true !!1 // true !!{} // true !![] // true所有假值(false、0、""、null、undefined、NaN)都会让&&短路跳过右侧、让||继续求值右侧;而其余值一律按真值处理。这与第 5 期 tip Differences betweenundefinedandnull中"两者均为 falsy"的结论一致——正因undefined是假值,第四节中的默认值技巧和第五节中的安全访问技巧才能成立。
七、深入二:回调守卫模式 callback && callback(err)
短路求值在异步编程中最常见的应用是"回调守卫":只在回调存在时才调用它。仓库第 54 期 tip How to use optional arguments in functions 中两次使用了这一模式:
// 传统写法 if (err) { return callback && callback(err); } // ES6 写法 if (err && callback) return callback(err);callback && callback(err)同时完成了两件事:callback为undefined或null时短路跳过,不会抛出callback is not a function异常;callback存在时正常调用并把err传给它。这是对第五节"安全访问"思想的直接延伸——不仅属性可以守卫,函数参数同样可以守卫。
八、深入三:函数式循环中的短路 —— .some 与 .every
短路求值不仅作用于操作数,也体现在数组迭代方法中。仓库第 58 期 tip Breaking or continuing loop in functional programming 指出:for循环可以用break提前终止,而.forEach无法 break;改用.some后,只要回调返回true,遍历立即停止(相当于短路):
[0, 1, 2, 3, 4].some(function(val, i) { if (val === 2) { return true; // break:停止遍历 } console.log(val); // 你的业务代码 }); // 输出: 0, 1用.every也能达到类似效果,只是需要返回与.some相反的布尔值。这种"返回即短路"的迭代语义,与&&/||的"结果已定即跳过"在思想上完全同源,是短路思维在更高层抽象中的体现。
九、注意事项与边界陷阱
- 假值陷阱:
name || 'Bar'对''、0、NaN等"有意义的假值"也会强制替换成默认值。如果业务上需要保留0或空字符串,||默认值就不适用,应改用显式判断name === undefined或 ES6 默认参数function foo(name = 'Bar'){}(ES6 默认参数只对undefined生效)。 - 可读性权衡:
condition && dosomething()适合条件简短、副作用清晰的行内场景;条件复杂时,传统if语句的可读性与可调试性更优,不必强行压缩。 - 返回值是操作数本身:
a && b的结果不是布尔值,而是被"选中"的那个操作数(可能是a也可能是b的原值)。这在链式访问(如obj.a && obj.a.b && obj.a.b.c)中非常有用,但也要求开发者明确最终拿到的是真值/假值还是具体对象。 - 与
!!的配合:需要真正布尔结果时,可结合第 30 期 tip 的!!写法:!!(dog && dog.bark)得到标准布尔值,避免结果类型被操作数"污染"。
十、小结
短路求值是 JavaScript 中最实用也最容易被忽视的语言特性之一:&&表达"条件为真才执行"、||表达"条件为假才兜底",两者共同支撑起默认参数、安全属性访问、回调守卫等高频率实战写法。本指南中的全部示例均来自 jstips 仓库(英文原版见 _posts/en/javascript/2016-01-27-short-circuit-evaluation-in-js.md,中文版见 _posts/zh_CN/javascript/2016-01-27-short-circuit-evaluation-in-js.md),并可继续在 Three useful hacks、Converting truthy/falsy values to boolean、Use optional arguments 与 Break or continue loop in functional programming 等相邻 tip 中延伸阅读。掌握了求值规则与假值边界,就能安全、自信地在日常代码中运用这一简洁范式。
- 教程
【免费下载链接】jstips
This is about useful JS tips!
相关推荐
jstips 赋值简写指南:用复合运算符、短路求值与字面量写法精简 JavaScript 代码
jstips 赋值简写指南:用复合运算符、短路求值与字面量写法精简 JavaScript 代码 本文源自 jstips 仓库第 35 期技巧《Operadore
教程RSLint —— 让您的JavaScript和TypeScript代码更健壮的神器
RSLint —— 让您的JavaScript和TypeScript代码更健壮的神器 还在为JavaScript代码中的潜在错误而烦恼吗?还在使用缓慢的lint
jstips 第 35 期:JavaScript 赋值运算符与赋值简写技巧全解析
jstips 第 35 期:JavaScript 赋值运算符与赋值简写技巧全解析 本篇技术指南以 jstips https://link.gitcode.com
教程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考