[译] 我见过最好最详细的 JavaScript 关系的解释

简介: 你可以通过运行开发者工具来运行(图中)的每行代码来验证此关系的准确性。结果并不令人惊讶,但仍然令人失望。

TLDR:强迫自己使用三重等号(===)


我无意在Reddit上找到了这个JavaScript meme,它是我见过最好的抽象。


image.png


你可以通过运行开发者工具来运行(图中)的每行代码来验证此关系的准确性。结果并不令人惊讶,但仍然令人失望。


当然,这个小实验触发了我的兴趣...


这是怎么发生的?


凭借经验,我学会了接受JavaScript这滑稽的一面,同时感受它的松散。尽管如此,这个事件的细节仍然让我感到困惑。


正如Kyle Simpson所说...


"不管怎么说,我认为任何人都不会真正了解JS"


当这些案例出现时,最好查阅源代码--构建JavaScript的官方ECMAScript规范


有了这个规范,让我们深刻理解这里发生了什么。


板块1 - 引入强制


image.png


如果你在开发者控制台上运行0 == "0",为什么它返回true


0是一个数字,然后"0"是一个字符串,它们永远不应该相同的!大多数编程语言都遵守它。例如,Java中的0 == "0",会返回下面这个:


error: incomparable types: int and String


这很有道理。如果要比较Java中的intString,必须先把它们转换为相同的类型。


但这是JavaScript,你们呀!


当你通过==比较两个值时,其中一个值可能受到强制转换。


强制 - 自动将值从一种类型转换为另一种类型。


这里的自动是关键词。JavaScript不是在显式转换你的类型,而是在幕后帮你完成。


如果你有目的地利用它,这很方便,但如果你不知道它的含义,则可能有害。


这是关于它的官方ECMAScript语言规范。 我会解释相关部分:


If x is Number and y is String, return x == ToNumber(y)

译:如果 x 是数字类型,y 是字符串类型,将 y 转换成数字类型与 x 作比较后返回


所以我们的例子0 == "0"


因为 0 是一个数字类型,"0" 是一个字符串类型,则返回 0 == ToNumber("0")


我们的字符串"0"已经被秘密转换成数字0,现在我们有一个匹配了!


0 == "0" // true
// The second 0 became a number!
// so 0 equals 0 is true....


奇怪吧?好好习惯它,我们接着说~


板块2 - 数组也被强制


image.png


这种强制不仅仅限制于字符串,数字或布尔值等基本数据类型。这是我们的下一个比较:


0 == [] // true
// What happened...?


再次被强制了!我将解释规范的相关部分:


If x is String or Number and y is Object, return x == ToPrimitive(y)

译:如果 x 是字符串或数字类型,然后 y 是对象类型,将 y 转换为基本数据类型与 x 作比较后返回


这里有三件事:


1.是的,数组是对象


image.png


抱歉,刷新了你的认知。


2.空数组变成空字符串


再次根据规范,JS首先寻找一个对象的toString方法来强制转换它。


在数组的情况下,toString连接其所有元素并将它们作为字符串返回。


[1, 2, 3].toString() // "1,2,3"
['hello', 'world'].toString() // "hello,world"


因为我们的数组是空的,我们没内容去拼接!所以...


[].toString() // ""


规范中的ToPrimitive将空数组转换成空字符串。相关的参考在这里这里,方便你查阅(或解决疑惑)。


3.空字符串然后变成0


image.png


你不能把这些东西搞定。现在我们已经将数组强制变成"",我们又回到了第一个算法(规范)...


If x is Number and y is String, return x == ToNumber(y)


所以0==""


Since 0 is Number and "" is String, return 0 == ToNumber("")                                                                                                                      


ToNumber("")返回 0 。


因此,再一次是0==0...


网络异常,图片无法展示
|


板块3 - 快速回顾


image.png


这是正确的


0 == "0" // true


因为被强制转换成这个0 == ToNumber("0")


这也是正确的


0 == [] // true


因为强制转换执行两次:


  1. ToPrimitive([])转换为空字符串


  1. 然后ToNumber("")转换为 0 。


所以,告诉我...根据上面的规则,下面将返回什么?


"0" == []


板块4 - FALSE!


image.png


FALSE! 正确。


如果你明白规则,这部分是有意义的。


下面是我们的比较:


"0" == [] // false


再次参考规范:


If x is String or Number and y is Object, return x == ToPrimitive(y)


那就意味着...


Since "0" is String and [] is Object, return x == ToPrimitive([])


"0" == ""


"0"""都是字符串类型,所以JavaScript不需要再强制转换了。这就是为什么得到结果为false的原因。


总结


image.png


使用三重等号(===),然后晚上睡个好觉。


0 === "0" // false
0 === [] // false
"0" === [] // false


它完全避免强制转换,所以我猜它也更有效率!


但是('==='对于)性能的提升几乎毫无意义。




相关文章
|
7月前
|
JavaScript 前端开发 编译器
js开发: 请解释什么是Babel,以及它在项目中的作用。
**Babel是JavaScript编译器,将ES6+代码转为旧版JS以保证兼容性。它用于前端项目,功能包括语法转换、插件扩展、灵活配置和丰富的生态系统。Babel确保新特性的使用而不牺牲浏览器支持。** ```markdown - Babel: JavaScript编译器,转化ES6+到兼容旧环境的JS - 保障新语法在不同浏览器的运行 - 支持插件,扩展编译功能 - 灵活配置,适应项目需求 - 富强的生态系统,多样化开发需求 ```
61 4
|
7月前
|
开发框架 JavaScript 安全
js开发:请解释什么是Express框架,以及它在项目中的作用。
【4月更文挑战第24天】Express是Node.js的Web开发框架,简化路由管理,支持HTTP请求处理。它包含中间件系统用于日志、错误处理和静态文件服务,集成多种模板引擎如EJS、Jade、Pug。框架还提供安全中间件提升应用安全,并具有良好的可扩展性,便于项目功能扩展和开发效率提升。
131 3
|
7月前
|
存储 JavaScript 索引
js开发:请解释什么是ES6的Map和Set,以及它们与普通对象和数组的区别。
ES6引入了Map和Set数据结构。Map的键可以是任意类型且有序,与对象的字符串或符号键不同;Set存储唯一值,无重复。两者皆可迭代,支持for...of循环。Map有get、set、has、delete等方法,Set有add、delete、has方法。示例展示了Map和Set的基本操作。
109 3
|
7月前
|
存储 JavaScript 前端开发
解释 JavaScript 中的作用域和作用域链的概念。
【4月更文挑战第4天】JavaScript作用域定义了变量和函数的可见范围,静态决定于编码时。每个函数作为对象拥有`scope`属性,关联运行期上下文集合。执行上下文在函数执行时创建,定义执行环境,每次调用函数都会生成独特上下文。作用域链是按层级组织的作用域集合,自内向外查找变量。变量查找遵循从当前执行上下文到全局上下文的顺序,若找不到则抛出异常。
59 6
|
7月前
|
缓存 JavaScript 前端开发
js开发:请解释什么是Webpack,以及它在项目中的作用。
Webpack是开源的JavaScript模块打包器,用于前端项目构建,整合并优化JavaScript、CSS、图片等资源。它实现模块打包、代码分割以提升加载速度,同时进行资源优化和缓存。借助插件机制扩展功能,并支持热更新,加速开发流程。
67 4
|
7月前
|
缓存 JavaScript 数据安全/隐私保护
js开发:请解释什么是ES6的Proxy,以及它的用途。
`ES6`的`Proxy`对象用于创建一个代理,能拦截并自定义目标对象的访问和操作,应用于数据绑定、访问控制、函数调用的拦截与修改以及异步操作处理。
77 3
|
7月前
|
JavaScript
js开发:请解释什么是ES6的类(class),并说明它与传统构造函数的区别。
ES6的类提供了一种更简洁的面向对象编程方式,对比传统的构造函数,具有更好的可读性和可维护性。类使用`class`定义,`constructor`定义构造方法,`extends`实现继承,并可直接定义静态方法。示例展示了如何创建`Person`类、`Student`子类以及它们的方法调用。
90 2
|
7月前
|
开发框架 JavaScript 安全
js开发:请解释什么是Express框架,以及它在项目中的作用。
Express是Node.js的Web开发框架,简化路由管理,支持HTTP请求处理。它采用中间件系统增强功能,如日志和错误处理,集成多种模板引擎(EJS、Jade、Pug)用于HTML渲染,并提供安全中间件提升应用安全性。其可扩展性允许选用合适插件扩展功能,加速开发进程。
88 1
|
7月前
|
JavaScript 前端开发
js开发:请解释事件冒泡和事件捕获。
JavaScript中的事件处理有冒泡和捕获两种方式。事件冒泡是从子元素向上级元素传递,而事件捕获则从外层元素向内层传递。`addEventListener`的第三个参数可设定事件模式,`false`或不设为冒泡,`true`为捕获。示例代码展示了如何设置。
52 2
|
7月前
|
缓存 JavaScript 前端开发
js开发:请解释什么是Webpack,以及它在项目中的作用。
Webpack是开源的JavaScript模块打包器,用于前端项目构建,整合并优化JavaScript、CSS、图片等资源。它实现模块打包、代码分割以提升加载速度,同时进行资源优化和缓存。Webpack的插件机制可扩展功能,支持热更新以加速开发流程。
64 2