持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
先说结论: === 与 == :本质上的区别是会不会对操作数进行强制类型转换。
宽松相等(==)在操作数类型不相同的时候会进行强制类型转换,而严格相等(===)则不会进行强制类型转换。
但是有一个很重要的点,也是常见的一个误区——“==检查值是否相等,===检查值和类型是否相等”,这种说法容易让人产生误解。实际上,严格相等不进行强制类型转换并不代表它不检查操作数的类型,相反它们都会对操作数的类型进行检查,区别在于操作数类型不同时它们的处理方式。
由于宽松相等需要进行强制类型转换,所以它确实要比严格相等多花一些时间,但也只有微秒级别的差异罢了,在实际开发中更重要的还是看需不需要进行强制类型转换,需要就大胆用宽松相等(==),不需要就用严格相等(===)。
实际上在比较引用类型的时候,==和===的工作原理是相同的,都是比较引用地址是否相同,也就是比较两个值是否指向同一个引用地址,不发生强制类型转换。
如果两个值的类型相同,就只比较它们是否相等,比如123等于123,'qqq'等于'qqq'。
那么如果两个值的类型不同,当宽松相等(x==y)进行比较的时候,进行强制类型转换的规则是怎么样的呢?
例子:字符串与数字
const a = 123
const b = '123'
console.log(a == b) // true
上面这里是 a 转为 string 还是 b 转为 number 呢?
这里是将b转为number。
在ECMAScript中字符串与数字的宽松相等有以下规则:
- If Type(x) is Number and Type(y) is String,
return the result of the comparison x == ToNumber(y). - If Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.
也就是:
- 如果x是数字,y是字符串,会返回x == ToNumber(y)的结果
- 如果x是字符串,y是数字,会返回ToNumber(x) == y的结果
这里的ToNumber是ECMA规范中ES5定义的一个抽象方法,它可以将参数转为Number类型的值,详见ECMA
总而言之,如果是字符串和数字进行宽松相等(==)比较,那么总会把字符串强制类型转换成数字后再进行值的比较。
例子:其他类型与布尔值
const a = "123"
const b = true
console.log(a == b) // false
很多人会掉进一个坑里,认为"123"不是真值(truthy)吗?为什么不相等?
事实上这里的字符串"123"根本不涉及到布尔值的转换。
在ECMAScript中其他类型与布尔值的宽松相等有以下规则:
- If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
- If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
也就是:
- 如果x是布尔值,会返回ToNumber(x) == y的结果
- 如果y是布尔值,会返回x == ToNumber(y)的结果
"123"的确是真值,但是它在这里并不会发生布尔值的转换;而是将true转换为数字1,最后就是在进行"123" == 1的比较,结果当然就是false。
所以在任何时候都不建议使用
== true或者== false进行判断,因为由于隐式强制类型转换的存在,1==true、0==false等等这些判断都成立,但是它们可能都不是你想要的,这很容易让你的代码出现意料之外的问题,并且不容易被发现和排查到。
如果要判断某个值是否为布尔值,下面的写法都会更好:
if(a){}
if(Boolean(a)){}
if(!!a){}