jstips 第 68 期解读:为什么 JavaScript 相等比较应该使用 Object.is() 教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载本文基于 jstips 仓库 第 68 期中文技巧-in-equality-comparison.md)深入拆解 JavaScript 三种相等比较方案——宽松相等、严格相等与 ES6 新增的Object.is()——各自的适用边界重点剖析NaN、-0、0这三个连都无法正确处理的特例。读完本文你将掌握Object.is()的精确定义、与/的逐项行为差异以及在真实项目中安全判定NaN、区分正负零的实战写法。一、为什么不可靠类型转换带来的意外结果JavaScript 是弱类型语言这一点在相等比较上表现得尤为突出。使用双等号时引擎会在必要时执行类型转换coercion——把两个操作数中的其中一个转换成另一个的类型然后再比较。这种隐式转换常常产生与直觉相悖的结果。文档第 68 期原文-in-equality-comparison.md#L15-L21)给出了三个典型反例0 //true null undefined //true [1] true //true逐个来看0 字符串 一个空格被转换为数字0于是两边相等null undefined规定null与undefined互相相等这是规范中的特殊规则而不是类型转换的结果[1] true数组[1]先被转换为字符串1再被转换为数字1而true转换为数字也是1因此相等。对于以上规则仓库中另有一篇技巧可互相印证第 05 期「undefined 与 null 的区别」明确指出null undefined // true null undefined // false可见宽松相等的语义高度依赖隐式转换与特殊规则条件判断一旦复杂很难凭直觉预测结果是生产代码中 bug 的高发区。二、更严格但NaN让防线出现缺口为了解决的类型转换问题JavaScript 提供了全等操作符。它不会进行任何类型转换要求值相同且类型相同才返回true。仓库中的 第 24 期技巧「使用而不是」给出了一系列直观对照[10] 10 // 为 true [10] 10 // 为 false 10 10 // 为 true 10 10 // 为 false [] 0 // 为 true [] 0 // 为 false false // 为 true 但 true a 为false false // 为 false但是并不是相等比较的终点。文档第 68 期原文-in-equality-comparison.md#L25-L27)指出使用你仍然可能得到这样的结果NaN NaN //falseNaNNot-a-Number代表非数字它有一个特殊性质它不等于任何值甚至不等于它自己。在的语义下NaN NaN为false。这意味着用if (value NaN)判断某个值是否为NaN永远不成立对NaN做缓存、去重、集合判等时全部失效。这就是严格相等的缺口它在绝大多数场景下足够严格但在NaN与符号零-0/0这两个边界上行为并不符合数学直觉。三、ES6 的Object.is()更精确的相等比较好消息是ES6ES2015中新增了Object.is()方法。文档第 68 期原文-in-equality-comparison.md#L29-L36)指出它拥有的所有特性而且更精确在NaN等特殊案例中表现出色。Object.is(0 , ); //false Object.is(null, undefined); //false Object.is([1], true); //false Object.is(NaN, NaN); //true与前面对照比较表达式Object.is()0 true发生类型转换falsefalsenull undefinedtrue规范特殊规则falsefalse[1] truetrue数组与布尔均转数字falsefalseNaN NaNfalsefalsetrue可以看到Object.is()完全抛弃了的隐式转换行为与基本一致唯一的关键差异集中在NaN与符号零上——这正是它更精确的价值所在。从 ECMAScript 规范看Object.is()采用SameValue语义仅当两个值类型相同、值相同且符号零被视为不同时返回true。它不像那样做任何类型转换也不像那样把NaN排除在相等之外。四、深入边界NaN、-0与0文档特别转述了 Mozilla 团队的观点第 68 期原文-in-equality-comparison.md#L38)不要简单地说Object.is()比更严格更恰当的理解是——关注这个方法如何处理NaN、-0和0。展开来看三者在这三个特例上的完整对照如下比较表达式Object.is()NaN与NaNfalsefalsetrue-0与0即-0与0truetruefalse-0与-0truetruetrue0与0即0与0truetruetrue由此可以总结Object.is()的判定规则若两者都是NaN返回true与相反若一个是-0、另一个是0返回false与相反其余情况行为与完全一致不进行任何类型转换。这解释了为什么说它更好、更精确数学意义上NaN与NaN是同一个值-0与0是符号不同的两个值而Object.is()恰好忠实反映了这两种语义。原文档以一张对比图表呈现了上述全部差异图表位于 英文原版-in-equality-comparison.md) 与 繁体中文版-in-equality-comparison.md) 中本节的表格即为该图表的完整文字化还原。五、实战场景什么时候应该使用Object.is()综合前文Object.is()的实战价值集中在以下三类场景1. 判定某个值是否为NaN这是最典型的应用。由于NaN NaN为false任何基于的 NaN 检测都会失效const value Number(not-a-number); // NaN value NaN // false永远不成立 Object.is(value, NaN) // true可靠需要说明的是若你只是想检测 NaNNumber.isNaN(value)同样是专门的内建工具Object.is()的优势在于它是通用的同一性判定不局限于 NaN 一种场景。2. 区分-0与0某些计算如除法、解析、数学函数可能产生负零而会把-0与0视为相等导致无法区分-0 0 // true 无法区分 Object.is(-0, 0) // falseObject.is 可以区分 Object.is(-0, -0) // true在需要精确感知符号的场景例如绘图坐标、统计系统、科学计算中这一区分至关重要。3. 与集合语义衔接理解 SameValue 与 SameValueZeroObject.is()使用的是 SameValue 语义而 ES 规范中Set、Map、Array.prototype.includes等内部使用的是SameValueZero语义——后者与Object.is()几乎一致唯一区别是把-0与0视为相等。因此Object.is()可以视为在规范相等性家族中最严格的一档理解它能帮助你更好地预判Set/Map的判重行为。六、仓库延伸阅读jstips 仓库围绕相等比较这一主题形成了完整的技巧链建议按顺序阅读第 68 期 · 为什么你应该在相等比较中使用 Object.is()-in-equality-comparison.md)本文主体另有 英文原版-in-equality-comparison.md) 与 繁体中文版-in-equality-comparison.md) 可对照阅读第 24 期 · 使用而不是与的类型转换差异与速查示例第 05 期 · undefined 与 null 的区别从null undefined到null undefined的特殊规则详解。七、结论回到文档的核心观点因隐式类型转换而不可靠因NaN与符号零而存在边界缺口而 ES6 的Object.is()在保留全部严格性的基础上以 SameValue 语义正确处理了NaN、-0、0三个特例。虽然 Mozilla 团队提醒我们不应简单地说它更严格但在真实应用中凡是涉及 NaN 判定、正负零区分或通用同一性比较的地方Object.is()都是比和更稳妥的实践选择。赞分享教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载相关推荐GetQzonehistory 一键完整导出 QQ 空间历史说说为 ExcelGetQzonehistory 一键完整导出 QQ 空间历史说说为 Excel QQ 空间页面只展示近期动态老说说其实还留在后台的历史消息列表里。GetQzo网页爬虫数据分析Dinero.js比较操作为什么货币比较不能直接用JavaScript运算符Dinero.js比较操作为什么货币比较不能直接用JavaScript运算符 在JavaScript中处理货币计算时很多开发者会遇到一个常见陷阱试图使用标金融科技PocketFlow Gradio 构建 Human-in-the-LoopHITL工作流应用实战PocketFlow Gradio 构建 Human in the LoopHITL工作流应用实战 本教程以 PocketFlow 官方 cookboo人工智能大模型AI Agent工作流自动化RAG上一篇agency-agents 仓库网络工程师 Agent 实战指南Cisco/Juniper/Palo Alto 多厂商路由交换与防火墙配置、排障与变更管理下一篇Ubuntu Tweak 项目教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考