重新学习 == 和 ===

60 阅读4分钟

在上班摸鱼的时候重新回看了一下经典的小黄书系列,重新学习了一下 宽松比较和严格比较

宽松相等(loose equals)== 和严格相等(strict equals)=== 都用来判断两个值是否“相等”,但是它们之间有一个很重要的区别,特别是在判断条件上。

发现了有一个之前一直有被误导的地方就是, ==检查值是否相等,===检查值和类型是否相等

正确的解释应该是 ==允许在相等比较中进行强制类型转换,而===不允许

小黄书中的原话: 常见的误区是“==检查值是否相等,===检查值和类型是否相等”。听起来蛮有道理,然而还不够准确。很多JavaScript的书籍和博客也是这样来解释的,但是很遗憾他们都错了。

在类型相同的情况下

基本数据类型 直接比较值

5 == 5 // true
5 ===5 // true
hello == hello //true
hello === hello  //true
true == true // true
true === true // true

复杂数据类型 比较的是引用地址

let a = {}
let b = {}

a == b // false
a === b // false

let c = b
c == b // true
c === b // true

如果比较的是两个不同的数据类型

nullundefined

null == undefined // true
null === undefined // true

nullundefined 之间的 == 也涉及隐式强制类型转换

在 == 中 null 和 undefined 相等(它们也与其自身相等),除此之外其他值都不存在这种情况

也就是说,在==中null和undefined是一回事,可以相互进行隐式强制类型转换

let a = null; 
let b; 
a == b; // true 
a == null; // true 
b == null; // true
a == false; // false
b == false; // false 
a == ""; // false
b == ""; // false 
a == 0; // false 
b == 0; // false

数字与字符串比较

55 == '55' // true
55 === '55' // false

由于没有强制类型转换 55 === '55', 55 与 '55' 为false, 55 与 '55'不相等

而 55 == '55', 是宽松相等, 对其中之一进行了,强制类型转换

具体是如何转换的?

是数字的55转换成了字符串的'55',还是字符串的'55'转换成了数字的55呢?

es5规范中的定义

简单来说就是, 无论前者是字符串或者是数字(或者反之),都将字符串类型转换成数字类型进行比较

55 ==='55'  会转换成 55 === ToNumber('55') 来进行比较

布尔值与其他类型

 true == '5' // false
 false == '5' // false

在布尔值的比较中,会将布尔值 false 转换成 0 , true 转换成 1 来进行比较

true == '5' ==> 1 == '5' ==> 1 == 5 
false =='5' ==> 0 == '5' ==> 0 == 5

这里有一个疑问就是 字符串的 5 是一个真值,但是为什么 不等于 true 其实他的流程是先将布尔值转换成 0 或者是 1 如果在转换后与其比较的是数字类型会直接进行比较,如果是其他类型会继续进行类型转换直至是数字类型为止,所以并不是 拿的 true 与 true 进行比较

let a = '5'
// 不要这样用,条件判断不成立:
if (a == true) { // .. } 
// 也不要这样用,条件判断不成立:
if (a === true) { // .. }
// 这样的显式用法没问题: 
if (a) { // .. } 
// 这样的显式用法更好: 
if (! ! a) { // .. } 
// 这样的显式用法也很好:
if (Boolean( a )) { // .. }

所以无论什么情况下都不要使用== true和== false(布尔值的宽松相等)

对象与非对象类型

5 == [5] // true
5 === [5] // false 类型不同

这里会将对象类型转换成基本数据类型之后再进行比较

5 == [5] ==> 5 ==> '5' ==> 5 == 5 

NaN 和任何值(包括它自己)比较都返回 false,不管是 == 还是 ===

NaN == NaN  // false
NaN === NaN // false

Alex Dorey(GitHub用户名@dorey)在GitHub上制作了一张图表,列出了各种相等比较的情况

epub_22806928_66.png

总结

左侧右侧== 结果=== 结果备注
nullundefinedtruefalse== 相等
数字字符串比较时字符串转换为数字false"42" == 42true
布尔值数字布尔值转换为 0/1falsetrue == 1true
对象原始类型对象转换为原始值false[1] == "1"true
数字NaNfalsefalseNaN 不等于任何值
空字符串数字 0true(空字符串为 0false"" == 0true
空字符串falsetruefalse"" == falsetrue
引用类型引用类型引用相同则相等引用相同则相等比较的是引用地址
  • 宽松相等(== :会进行隐式类型转换,这使得不同类型的值可以比较,但也会导致不可预测的行为。

  • 严格相等(=== :不会进行任何类型转换,因此类型和值都必须相同才返回 true

为了代码的可读性和避免潜在的错误,强烈建议使用严格相等(=== ,尤其在不需要类型转换的情况下。宽松相等虽然可以节省代码量,但也会带来不可预测的隐式类型转换问题,从而增加代码维护的复杂度和潜在错误

以上为个人学习记录,内容中可能存在理解或表达上的不足。如果您发现任何错误或有改进建议,欢迎指出,非常感谢您的帮助。