JavaScript 比较 和 逻辑运算符
JavaScript 比较与逻辑运算符深度解析比较运算符和逻辑运算符是 JavaScript 控制程序流程如if、while、for的核心。它们决定了代码的执行路径。一、比较运算符 (Comparison Operators)比较运算符用于比较两个值返回布尔值true或false。1. 相等性判断vs(核心重点)这是 JavaScript 中最容易出错的地方。运算符名称行为示例结果宽松相等 (Loose Equality)先进行类型转换再比较值5 5true严格相等 (Strict Equality)不转换类型值和类型必须完全相同5 5false!宽松不等先转换再比较不相等5 ! 5false!严格不等不转换比较不相等5 ! 5true为什么推荐的隐式类型转换规则非常复杂且反直觉容易导致 Bug。// 令人困惑的 行为console.log(0false);// true (false - 0)console.log(0);// true ( - 0)console.log(false);// true (两边都转成 0)console.log(nullundefined);// true (特殊规则)console.log([]false);// true ([] - - 0)console.log([]0);// true// 使用 则非常清晰console.log(0false);// falseconsole.log(0);// falseconsole.log(nullundefined);// false最佳实践永远优先使用和!。只有在明确需要类型转换的极少数场景下才使用。2. 大小比较运算符运算符描述示例结果大于5 3true小于5 3false大于等于5 5true小于等于5 3false比较时的类型转换陷阱当比较不同类型时JavaScript 会尝试将它们转换为数字进行比较。console.log(53);// true (5 - 5)console.log(102);// true (10 - 10)console.log(102);// false (字符串比较是按字符编码逐位比较1 2)console.log(true0);// true (true - 1)console.log(false1);// true (false - 0)console.log(1);// true ( - 0)console.log(a1);// false (a - NaN, NaN 与任何数比较都是 false)注意字符串比较是字典序逐字符比较 ASCII/Unicode 码不是数值大小。10 2是true因为1的编码小于2。如果需要数值比较请确保两边都是数字Number(10) Number(2)。3. 特殊值比较NaN(Not a Number)NaN与任何值包括它自己比较都返回false。console.log(NaNNaN);// falseconsole.log(NaNNaN);// false// 判断 NaN 的正确方法console.log(Number.isNaN(NaN));// true (推荐)console.log(isNaN(NaN));// true (旧方法会尝试转换类型)null和undefinednull undefined返回true。null undefined返回false。它们与其他任何值比较除了彼此都返回false。console.log(nullundefined);// trueconsole.log(null0);// falseconsole.log(null0);// true (null 转为 0)二、逻辑运算符 (Logical Operators)逻辑运算符用于组合布尔值或者在表达式中返回非布尔值。1. 逻辑与 ()规则如果第一个操作数为真返回第二个操作数否则返回第一个操作数。短路特性如果第一个操作数为假不会计算第二个操作数。// 返回第一个假值console.log(falseHello);// falseconsole.log(0Hello);// 0console.log(nullHello);// nullconsole.log(Hello);// // 返回第二个值如果第一个为真console.log(trueHello);// Helloconsole.log(12);// 2console.log(HiWorld);// World// 常用场景条件执行// 只有当 user 存在时才访问 user.nameletusernull;letnameuseruser.name;// name 为 null不会报错2. 逻辑或 (||)规则如果第一个操作数为真返回第一个操作数否则返回第二个操作数。短路特性如果第一个操作数为真不会计算第二个操作数。// 返回第一个真值console.log(true||World);// trueconsole.log(1||2);// 1console.log(Hi||World);// Hi// 返回第二个值如果第一个为假console.log(false||World);// Worldconsole.log(0||10);// 10console.log(null||Default);// Default// 常用场景设置默认值letusername;letdisplayNameusername||Guest;// Guest3. 空值合并运算符 (??) - ES2020规则如果左侧是null或undefined返回右侧否则返回左侧。区别||会把0,,false视为假值而??只关心null和undefined。letcount0;letprice;letisActivefalse;// 使用 || (会错误地覆盖有效值)console.log(count||10);// 10 (0 被当作假值)console.log(price||N/A);// N/A (空字符串被当作假值)console.log(isActive||true);// true// 使用 ?? (正确保留有效值)console.log(count??10);// 0 (0 是有效值)console.log(price??N/A);// (空字符串是有效值)console.log(isActive??true);// false// 推荐设置默认值时使用 ??letconfig{timeout:0};lettimeoutconfig.timeout??3000;// 0 (而不是 3000)4. 逻辑非 (!)规则将操作数转换为布尔值并取反。双重非 (!!)将任意值转换为布尔值。console.log(!true);// falseconsole.log(!0);// trueconsole.log(!Hello);// falseconsole.log(!null);// true// 转换为布尔值console.log(!!Hello);// trueconsole.log(!!0);// falseconsole.log(!!null);// false三、逻辑运算符的短路求值 (Short-Circuit Evaluation)这是逻辑运算符最强大的特性常用于优化性能和简化代码。1.的短路如果左边是假值右边根本不会执行。// 防止访问 null/undefined 属性functiongetName(user){returnuseruser.profileuser.profile.name;}// 传统写法// if (user user.profile) { return user.profile.name; }// return undefined;2.||的短路如果左边是真值右边根本不会执行。// 避免执行昂贵的函数调用letresultexpensiveCheck()||defaultValue;// 如果 expensiveCheck() 返回真值defaultValue 不会被计算3. 结合性逻辑运算符是从左到右结合的。// 等价于 (a b) cletresultabc;// 等价于 (a || b) || cletresulta||b||c;四、三元运算符 (Ternary Operator)唯一的三目运算符是if...else的简写。语法条件 ? 表达式1 : 表达式2letage20;letstatusage18?成年:未成年;console.log(status);// 成年// 嵌套使用 (不推荐降低可读性)letscore85;letgradescore90?A:score80?B:C;与逻辑运算符的对比三元运算符返回值。逻辑运算符返回操作数的值不一定是布尔值。// 三元letxab?1:2;// 逻辑或 (如果 a b 为真返回 1否则返回 2)// 注意如果 a b 为真但 1 是假值 (不可能)逻辑或的行为会不同lety(ab)1||2;// 这种写法不推荐容易出错五、常见陷阱与最佳实践1. 陷阱和||的返回值不是布尔值letresultHelloWorld;console.log(result);// World (不是 true)if(result){console.log(Truthy);// 会执行}建议如果需要布尔值使用!!转换let bool !!(a b);2. 陷阱0和在||中失效letcount0;letdisplaycount||No count;// 显示 No count (错误)// 应该使用 ??letdisplaycount??No count;// 显示 0 (正确)3. 陷阱字符串比较console.log(102);// false (字符串比较)console.log(Number(10)Number(2));// true (数值比较)4. 最佳实践总结比较始终使用和!。默认值如果0,,false是有效值使用??。如果0,,false应被视为“无值”使用||。安全访问使用进行短路保护如obj obj.prop。可读性避免过度嵌套的三元运算符或复杂的逻辑表达式。六、速查表场景推荐运算符示例严格相等if (x 5)宽松相等(极少使用)if (x null)默认值 (0/有效)??let val x ?? 0;默认值 (0/无效)条件执行user user.login()布尔转换!!let bool !!value;三元判断? :age 18 ? Adult : Child掌握这些细节你的 JavaScript 代码将更加健壮、简洁且不易出错