ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

现代 JavaScript 教程之逻辑运算符完全指南:`||`、``、`!` 的真值查找、短路求值与优先级

现代 JavaScript 教程之逻辑运算符完全指南:`||`、``、`!` 的真值查找、短路求值与优先级 文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载本文是《现代 JavaScript 教程》zh.javascript.info1-js/02-first-steps/11-logical-operators/article.md 一节的深度成文版。JavaScript 中共有四个逻辑运算符||或、与、!非与??空值合并运算符将在后续小节专门介绍。本文将围绕前三个运算符讲清它们处理任意类型值的求值规则、短路行为、优先级并配合仓库内附带的 8 组练习题位于 11-logical-operators 目录 下进行实战验证。读完本文你将能熟练用||取第一个真值、用取第一个假值、用!!做布尔转换并准确判断混合表达式的结果。从“布尔专用”到“任意类型”逻辑运算符的 JavaScript 特色虽然被称为“逻辑”运算符但在 JavaScript 中||、、!都可以被应用于任意类型的值而不只是布尔值它们的结果也同样可以是任意类型。这一点与传统编程语言有显著差异。在传统编程中逻辑或/与仅能操作布尔值只要参与运算的任意一个参数为true或运算返回true否则返回false。JavaScript 保留了这一语义当操作数是布尔值时但额外引入了一套针对任意值的求值算法使其用途大幅扩展。如果操作数不是布尔值那么在运算过程中它会被转化为布尔值来参与判断。例如数字1被当作true真值数字0被当作false假值if (1 || 0) { // 工作原理相当于 if( true || false ) alert( truthy! ); }||或从真值表到条件判断两个竖线符号表示“或”运算符result a || b;操作数为布尔值时的四种组合alert( true || true ); // true alert( false || true ); // true alert( true || false ); // true alert( false || false ); // false除了两个操作数都是false的情况结果都是true。在if中测试“任一条件成立”大多数情况下逻辑或||被用在if语句中用来测试是否有任何给定的条件为truelet hour 9; if (hour 10 || hour 18) { alert( The office is closed. ); }也可以传入更多的条件只要其中任意一个为真整个if分支就会执行let hour 12; let isWeekend true; if (hour 10 || hour 18 || isWeekend) { alert( The office is closed. ); // 是周末 }或运算寻找第一个真值上文所述的处理方式多少有些“传统”。JavaScript 的或运算还有一个“附加”特性给定多个参与或运算的值result value1 || value2 || value3;或运算符||执行如下算法从左到右依次计算操作数处理每一个操作数时都将其转化为布尔值。如果结果是true就停止计算返回这个操作数的初始值如果所有操作数都被计算过即转换结果都是false则返回最后一个操作数。注意返回的值是操作数的初始形式不会做布尔转换。换句话说一个||链返回的是第一个真值如果不存在真值就返回该链的最后一个值。例如alert( 1 || 0 ); // 11 是真值 alert( null || 1 ); // 11 是第一个真值 alert( null || 0 || 1 ); // 1第一个真值 alert( undefined || null || 0 ); // 0都是假值返回最后一个值与“纯粹的、只处理布尔值的或运算”相比这个规则引出了几个非常实用的用法。用法一获取变量列表中的第一个真值例如有变量firstName、lastName和nickName它们都是可选的可能为undefined也可能是空字符串等假值。用||选出有数据的那一个若都没有则回退到默认值Anonymouslet firstName ; let lastName ; let nickName SuperCoder; alert( firstName || lastName || nickName || Anonymous); // SuperCoder如果所有变量的值都为假结果就是Anonymous。这是一种非常常见的“取默认值/回退值”写法。用法二短路求值Short-circuit evaluation||的另一个重要特性是“短路求值”它对其参数从左到右进行处理一旦遇到第一个真值就立即返回该值而不再处理其余参数。当操作数不仅仅是一个值而是带有副作用的表达式例如变量赋值或函数调用时这一特性的重要性就显现出来了。在下面这个例子中只有第二条信息会被打印true || alert(not printed); false || alert(printed);第一行中||在遇到true时立即停止计算所以后面的alert根本没有执行。有时人们利用这个特性实现“仅当左侧条件为假时才执行右侧命令”的效果。与真值表与条件判断两个符号表示与运算符result a b;操作数为布尔值时的四种组合在传统编程中当两个操作数都是真值时与运算返回true否则返回falsealert( true true ); // true alert( false true ); // false alert( true false ); // false alert( false false ); // false带有if语句的示例let hour 12; let minute 30; if (hour 12 minute 30) { alert( Time is 12:30 ); }就像或运算一样与运算的操作数也可以是任意类型的值if (1 0) { // 作为 true false 来执行 alert( wont work, because the result is falsy ); }与运算寻找第一个假值给出多个参加与运算的值result value1 value2 value3;与运算执行如下算法从左到右依次计算操作数处理每一个操作数时都将其转化为布尔值。如果结果是false就停止计算返回这个操作数的初始值如果所有操作数都被计算过例如都是真值则返回最后一个操作数。换句话说与运算返回第一个假值如果没有假值就返回最后一个值。这条规则与或运算非常像区别仅在于与运算返回第一个假值而或运算返回第一个真值。例如// 如果第一个操作数是真值 // 与运算返回第二个操作数 alert( 1 0 ); // 0 alert( 1 5 ); // 5 // 如果第一个操作数是假值 // 与运算将直接返回它。第二个操作数会被忽略 alert( null 5 ); // null alert( 0 no matter what ); // 0也可以在一行代码上串联多个值观察第一个假值是如何被返回的alert( 1 2 null 3 ); // null如果所有的值都是真值最后一个值将会被返回alert( 1 2 3 ); // 3最后一个值与运算在或运算||之前进行与运算的优先级比或运算||要高。所以代码a b || c d跟加了括号的(a b) || (c d)完全一样。不要用||或来取代if有时候有人会将与运算符当作“简化if”的一种方式。例如let x 1; (x 0) alert( Greater than zero! );右边的代码只有运算抵达那里才能被执行也就是当且仅当(x 0)为真。所以它基本等价于let x 1; if (x 0) alert( Greater than zero! );虽然用写出的变体看起来更短但if更明显也往往更具可读性。因此建议根据每种语法结构的用途来使用想要if就用if想要逻辑与就用。!非取反与布尔转换感叹符号!表示布尔非运算符语法相当简单result !value;逻辑非运算符接受一个参数并按如下两步运作将操作数转化为布尔类型true/false返回相反的值。例如alert( !true ); // false alert( !0 ); // true用!!把任意值转为布尔值两个非运算!!常被用来将某个值转化为布尔类型alert( !!non-empty string ); // true alert( !!null ); // false原理是第一个非运算将该值转化为布尔类型并取反第二个非运算再次取反最终得到任意值到布尔值的转换。等价地也可以使用内建的Boolean函数效果相同但写法略显冗长alert( Boolean(non-empty string) ); // true alert( Boolean(null) ); // false非运算符的优先级非运算符!的优先级在所有逻辑运算符里最高所以它总是先于和||执行。三运算符速查对照运算符名称布尔语义任意值语义返回结果\|\|或任一为true则true返回第一个真值无真值则返回最后一个值操作数初始值不做布尔转换与全为true才true返回第一个假值无假值则返回最后一个值操作数初始值不做布尔转换!非取反先转布尔再取反布尔值??空值合并见后续小节返回第一个非null/undefined的值操作数初始值优先级从高到低大致为!||??的优先级与||的关系将在下一篇文章中详细说明。实战演练仓库内置练习题精讲本节对应仓库 11-logical-operators 目录 下的 8 组练习每个练习包含task.md与solution.md用于验证上述全部规则。练习 1alert( null || 2 || undefined )输出什么对应文件task.md 与 solution.md。结果是2因为它是这个链中的第一个真值null是假值被跳过2是真值立即返回undefined不再被计算。练习 2alert( alert(1) || 2 || alert(3) )输出什么对应文件task.md 与 solution.md。答案是首先是1然后是2。对alert的调用没有返回值或者说返回undefined。执行过程为||先计算左值alert(1)于是显示第一条信息1alert返回undefined假值||继续检查第二个操作数以寻找真值第二个操作数2是真值执行中断2被返回并由外层alert显示。这里不会显示3因为运算没有抵达alert(3)—— 这正是短路求值的体现。练习 3alert( 1 null 2 )输出什么对应文件task.md 与 solution.md。答案是null因为它是列表中第一个假值。练习 4alert( alert(1) alert(2) )输出什么对应文件task.md 与 solution.md。答案是1然后undefined。调用alert返回undefined因此计算了左操作数显示1后立即停止因为undefined是假值——寻找假值并返回它所以运算结束alert(2)不会执行。练习 5alert( null || 2 3 || 4 )输出什么对应文件task.md 与 solution.md。答案是3。因为与运算的优先级比||高它第一个被执行2 3的结果是3两个都是真值返回最后一个。于是表达式变成null || 3 || 4现在的结果就是第一个真值3。这道题综合验证了“优先于||”与“||取第一个真值”两条规则。练习 6检查值是否位于闭区间内对应文件task.md。要求写出if条件检查age是否位于14到90的闭区间即age可以取14或90。正确写法是同时用两个比较表达式并以连接if (age 14 age 90) { // 在闭区间内 }这道题展示了在范围校验中的典型用法只有当两个条件同时成立时整体才为真。练习 7关于if的问题对应文件task.md。分析下面三个if中哪些alert会执行if (-1 || 0) alert( first ); if (-1 0) alert( second ); if (null || -1 1) alert( third );逐行推演-1 || 0-1是真值||返回-1条件成立first会执行-1 0-1是真值继续计算00是假值返回0条件为假second不会执行null || -1 1先按优先级计算-1 1两者都是真值返回最后一个1表达式变为null || 11是真值条件成立third会执行。本题再次印证先于||计算而if只根据最终返回值的布尔真伪决定分支是否执行。练习 8登录校验综合实战对应文件task.md仓库中并附有登录流程示意图 ifelse_task.svg要求使用prompt实现登录校验如果访问者输入Admin再用prompt获取密码如果用户名为空或按下Esc此时prompt返回null显示Canceled其他字符串显示I dont know you密码校验输入TheMaster显示Welcome!其他字符串显示Wrong password空字符串或取消输入显示Canceled.。题目提示使用嵌套的if块以保证代码可读性并注意prompt的两个边界行为输入空字符串会得到按下Esc会得到null。一种符合要求的参考实现结合||的短路特性处理“空或取消”let userName prompt(Whos there?, ); if (userName Admin) { let pass prompt(Password?, ); if (pass TheMaster) { alert(Welcome!); } else if (pass || pass null) { alert(Canceled.); } else { alert(Wrong password); } } else if (userName || userName null) { alert(Canceled); } else { alert(I dont know you); }本题把||判断空值或取消、比较运算符与嵌套if/else综合运用在一个贴近真实业务的场景中是本节知识的收官练习。小结||返回第一个真值若无真值则返回最后一个值返回第一个假值若无假值则返回最后一个值——两者都返回操作数的初始值不做布尔转换。两者都从左到右短路求值||在遇到真值时停止在遇到假值时停止因此右侧带副作用的表达式可能根本不会执行。优先级从高到低依次为!、、||混合书写时务必按此顺序推演或直接用括号明确意图。!用于取反!!与Boolean()等价用于把任意值转为布尔类型。尽管可以“模拟”if但可读性优先逻辑运算符应各司其职。下一篇文章将介绍第四个逻辑运算符??空值合并运算符它专门用于从null/undefined中取回退值与本文的||在“假值”语义上存在关键差异值得对比学习。赞分享文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载相关推荐现代 JavaScript 教程if 条件中的逻辑运算求值——|| 与 的真值查找、优先级与短路执行解析现代 JavaScript 教程if 条件中的逻辑运算求值—— || 与 的真值查找、优先级与短路执行解析 本篇技术指南以《现代 JavaScript文档教程前端JavaScript 逻辑运算符优先级与短路求值详解 alert( null || 2 3 || 4 ) 的求值过程JavaScript 逻辑运算符优先级与短路求值详解 alert null || 2 3 || 4 的求值过程 null || 2 3 || 4文档教程前端OPA Rego 逻辑运算符 and / or 完全指南表达式求值、短路、优先级与作用域规则OPA Rego 逻辑运算符 and / or 完全指南表达式求值、短路、优先级与作用域规则 and 与 or 是 Open Policy AgentOPA后端认证鉴权云原生上一篇Gentelella数据可视化终极指南从图表选择到交互设计的最佳实践下一篇Gentelella动画性能优化CSS硬件加速与JavaScript节流创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表