面试官 :[] == ! [] 为什么返回 true ?

本文的讲解是建立在类型转换的基础上,如果对类型转换机制不了解的同学可以先阅读一下我的上一篇文章(看了一天的官方文档,终于搞懂了 JS 类型转换机制 - 掘金 (juejin.cn))

在 JavaScript 学习过程中,往往出现一些与我们常理相违背的结果,比如我们今天的论题[] == ![] ,它的返回的结果竟然是true ,这着实让初学者感到困惑。因为根据直觉,[]和![]两者应该是不相等的。面试官恰恰就会抓住这一点,对程序员们进行考察。

而本文将结合官方文档对该题进行深度剖析。

看看官方文档怎么说

关于 ==

关于==,文档这样描述:Annotated ES5 11.9.1

根据官方文档,我总结了以下 == 的隐式转换规则,一些简单的就忽略掉了:

  1. 类型相同的比较:

    (1)如果类型是 Undefined 或 Null,返回 true。

    js 复制代码
    null == null; // true

    (2)如果一个是 +0,另一个是 -0,返回 true:

    js 复制代码
    +0 == -0; // true

    (3)如果类型是对象,二者引用同一个对象,返回 true,反之返回 false。

    js 复制代码
    {} == {}; // false
  2. null 和 undefined 比较: 仅当它们之间的比较时,返回 true。

js 复制代码
null == undefined; // true
  1. NaN 比较: NaN 与任何值比较都返回 false,包括NaN自己。
js 复制代码
NaN == NaN;   // false
  1. 字符串与数字比较: 如果其中一个操作数是字符串,另一个是数字,将字符串转换为数字,然后进行比较。
js 复制代码
'5' == 5;   // true,将字符串 '5' 转换为数字 5 进行比较
  1. 布尔值与非布尔值比较: 布尔值无法直接比较,需先将布尔值转换为数字(true 转换为 1,false 转换为 0),非布尔值也需要转换成数字再比较。
js 复制代码
true == 1;  // true,将布尔值 true 转换为数字 1 进行比较
false == '123'; // false,将布尔值 false 转换为数字 0 ,将字符串 '123' 转换为数字 123 进行比较
  1. 对象与原始类型比较: 如果其中一个是对象,另一个是原始类型,将对象通过 ToPrimitive 转换为原始类型,然后进行比较。(即如果原始类型为字符串,则对象转换成字符串再比较;如果原始类为布尔值,则将布尔值与对象都转换成数字进行比较;如果原始类为数字,则将对象转换成数字进行比较。)

举个例子:

js 复制代码
{} == 1;  //false

ToPrimitive 在我的上篇文章(看了一天的官方文档,终于搞懂了 JS 类型转换机制)中详细介绍过,这里我们直接当做公式套用。

ToPrimitive(obj, Number) ==> Number({})

  1. 如果 obj 是基本类型,直接返回
  2. 否则,调用 valueOf 方法,如果得到原始值,则返回
  3. 否则,调用 toString 方法,如果得到原始值,则返回
  4. 否则,报错

首先{}先被ToPrimitive转换成字符串"[object Object]",就相当于直接判断 "[object Object]" == 1,字符串与数字的比较中,又要将字符串转换成数字,"object Object"转换成数字为 NaN,而NaN 与任何值比较都为 false。

所以 {} == 1 返回 false。

  1. 关系转换图如下:

回到[] == ! []

这里判断[]与![],两边都是对象,那怎么比呢,我们发现右边还有一个!,我们知道!的优先级是要大于==的,那么先进行非运算。

关于 !

关于!,文档这样描述:Annotated ES5 11.4.9

上表为各数据类型转换成布尔值的结果。

简而言之,!这个运算符会进行两步操作:

  1. 对!后面的操作数转换成布尔值

  2. 将这个布尔值取反

于是我们判断![],将[]转换成布尔值,我们在官方文档中就知道了,任何对象转换成布尔值都得到ture,然后在取反,得到![]为false。

最终判断

原式[] == ![]经过!运算将等式右边转换成了 false。即[] == false。

接着,根据==隐式转换规则,等式两边为对象和布尔,那么它们都应该转换成数字进行比较。

[]经过ToPrimitive会被转换成字符串""。再将等号两边的字符串""和布尔值false转换成数字 0 ,得到 0 == 0 。打印得到 true。

总结

所以实际在进行[] == ! []判断时,在JS引擎内部,会将这行代码执行成这个样子:

js 复制代码
[] == ![]

[] == !true // 将空数组这个对象类型转换成布尔值

[] == false // ! 运算符对 true 进行取反

'' == false // 对 [] 进行 ToPrimitive 操作,返回一个空对象 

0 == 0 // 将等号两边都转换成数字类型

最后

看到这里,恭喜你又拿下一道大厂面试题!

希望这篇文章能够为你提供帮助,如果你还有不懂之处,可以反复阅读,或者在评论区留言,学习是一个循序渐进,敢于试错的过程,我们顶峰相见!

我的Gitee: CodeSpace (gitee.com)

技术小白记录学习过程,有错误或不解的地方还请评论区留言,如果这篇文章对你有所帮助请 "点赞 收藏+关注" ,感谢支持!!

相关推荐
lpfasd1232 小时前
node-sass 停止维护!老项目迁移 Dart Sass 完整教程
前端·rust·sass
考研保研资料分享3 小时前
2022年马理论保研复盘:南师大原著题、首师大追问与上财选择
面试
考研保研资料分享4 小时前
2022编辑出版跨保西北大学中国史:五校面试与九月补材料
面试·职场和发展
Data analyse4565 小时前
rnweb 回放数据量太大怎么办?分片存储与断点续传的实现思路
前端·网络·算法·数据分析
xiaogai_gai5 小时前
金蝶收料通知单查询策略实战教程:从源系统拉取到中间层落地的完整路径
java·前端·数据库
环境栈笔记6 小时前
指纹浏览器 WebRTC 怎么设置?从 ICE 候选、代理出口到功能验证
前端·人工智能·后端·自动化
赵大仁6 小时前
官网性能优化实战:LCP 3.2s → 2.1s、CLS 0.107 → 0,以及被我推翻的 6 个判断
前端·性能优化·cls·lcp·core web vitals
xiancai_xianyu6 小时前
Text2SQL落地生产库前,SQL要过哪三道闸
前端·数据库·sql·sql注入·text2sql·ai agent开发·企业级ai框架
小羊没烦恼!6 小时前
T-SQL查询进阶--理解SQL SERVER中的分区表
服务器·开发语言·前端·javascript·html
史瓦辛格7 小时前
给 DeepSeek Harness 写费用插件:把「这次会话花了多少钱」算准
前端·deepseek