前言
判断两个变量是否相等是编程中最重要的操作之一。许多程序员为了省事,用的都是 == 操作符。
这并不是一个好习惯,可能导致难以检测的 bug,但我们不可避免地会接触到这类代码,面试中也经常出这类题目。
来做几道题,看看你究竟是否掌握了抽象比较 == 的类型转化规则
题目
你能自信的做出下面10道题吗?
// 第一题
console.log(1 == '1a')
// 第二题
console.log(.1 == '.1')
// 第三题
console.log([] == false)
// 第四题
console.log({} == '')
// 第五题
console.log({} == '[object Object]')
// 第六题
const obj = {
toString() {
return 1
},
}
console.log(obj == 1)
// 第七题
const obj = {
valueOf() {
return 0
},
toString() {
return '1'
},
}
console.log(obj == '1')
// 第八题
const obj = {
valueOf() {},
}
console.log(obj == undefined)
// 第九题
const obj1 = {
valueOf() {
return 0
},
}
const obj2 = Object.create(obj1)
obj2.toString = () => '1'
console.log(obj2 == 1)
// 第十题
const obj = {
toString() {
return {
valueOf() {
return 1
},
toString() {
return 0
},
}
},
}
console.log(obj == 0)
规则总结(省事看这里)
进行 == 比较时,从上到下匹配这些规则。
-
如果操作数具有相同的类型,则将它们进行如下比较:
-
基础数据类型:仅当两个操作数具有相同的字面量时才返回
true。 -
引用数据类型:仅当两个操作数都引用同一个对象时才返回
true。 -
0+0-0视为相同的值,NaN与NaN不相等。
-
-
如果一个操作数是
null或undefined,另一个操作数也是null或undefined,则返回true,否则返回false。 -
如果两个操作数是不同类型的,则会尝试将它们转换为相同类型:
-
如果操作数中有
Boolean,先将true转换为1,false转化为0。 -
当数字与字符串或 BigInt 进行比较时,会使用
Number(xxx)的方式将字符串转化为数字,可能存在精度缺失。 -
如果操作数之一是引用数据类型,另一个是基础数据类型,按以下规则进行转换:
-
会先调用对象身上的
valueOf()方法,如果得到的是基础数据类型,则使用此结果与另一操作数比较。 -
如果对象的
valueOf()方法没有返回基础数据类型,再调用对象的toString()方法,如果得到的是基础数据类型,则使用此结果与另一操作数比较;如果还是引用数据类型,抛出TypeError: Cannot convert object to primitive value。 -
所有对象原生的
valueOf()方法都是返回对象自己本身。 -
大部分对象原生的
toString()方法返回的是'[object XXX]'类型的字符串,一部分对象重写了此方法,比如数组的toString()方法,返回的是数据调用join方法的结果。
-
-
答案解析
接下来公布答案:
false
true
true
false
true
true
false
false
false
// TypeError: Cannot convert object to primitive value
你做对了吗?
还不懂的话,来看看解析:
-
第一题:数字与字符串比较,使用
Number('1a')转换字符串返回NaN,与1不相等。 -
第二题:字面量
.1是数字0.1,使用Number('.1')返回也是0.1,相等。 -
第三题:先将
false转化为0,然后使用[]的toString方法,等同于[].join()返回'',然后使用Number('')返回0,相等。 -
第四题:
{}的toString方法返回'[object Object]',与''不相等。 -
第五题:
{}的toString方法返回'[object Object]',相等。 -
第六题:
obj的toString方法返回1,相等。 -
第七题:优先调用
obj的valueOf方法返回0,不相等。 -
第八题:其中有一操作数是
undefined,另一操作数不是null或undefined,直接返回false。 -
第九题:通过
Object.create以obj1为原型创建obj2,比较时优先调用obj2的valueOf方法返回0,即使是在原型链上,不相等。 -
第十题:
obj的valueOf方法与toString方法返回的都不是基础数据类型,报错TypeError: Cannot convert object to primitive value。
结语
如果文中有错误或不严谨的地方,请务必给予指正,十分感谢。
如果喜欢或者有所启发,欢迎点赞关注,鼓励一下新人作者。