一、数字和其他类型值比较
1、数字和布尔值,将布尔值转为数字
console.log(1 == true) // true
console.log(0 == false) // true
2、数字和字符串,将字符串转为数字
console.log(1 == '1') // true
console.log(1 == 'a') // false
3、数字和对象,将对象转为字符串再转为数字
console.log(1 == [1]) // true
二、字符串和其他类型值比较
1、字符串和布尔值,二者转成数字再进行比较
console.log('1' == true) // true
console.log('0' == false) // true
2、字符串和对象,将对象转为字符串
console.log('1,2,3' == [1, 2, 3]) // true
以上,基本遵循这个规律:
三、布尔值和其他类型值比较
布尔值和数字比较时,布尔值先转为数字再比较;布尔值和字符串比较时,二者都要转为数字再比较。
所以,现在讨论布尔值和对象比较。它俩进行比较时,将布尔值转为数字,将对象转为字符串再转为数字
console.log(true == [1]) // true
console.log(false == []) // true
[1]转为字符串为'1',再转为数字为1,true转数字为1
[]转为字符串为'',再转为数字为0,false转为数字为0
看这个例子:
console.log(false == ![]) // true
其中,![]
是布尔值,![]
为false
四、undefined和null比较
console.log(undefined == null)
五、对象和原始值的比较
当对象隐式转换为原始值时,会经过以下的步骤:
- 如果有Symbol.toPrimitive方法,则先调用
- 调用valueOf,如果可以转成原来的类型,则返回
- 调用toString,如果可以转成原来的类型,则返回
- 如果没有返回原始值,则会报错
const obj = {
[Symbol.toPrimitive]() {
return 1
},
valueOf() {
return 2
},
toString() {
return 3
}
}
console.log(obj == 1) // true
在此例中,如果将Symbol.toPrimitive方法注释掉,则obj == 2
六、一道面试题:如何使a == 1 && a == 2 && a == 3
返回true
1、a对象中调用任意一个方法都可以做到返回true
const a = {
i: 1,
[Symbol.toPrimitive]() {
return this.i++
},
valueOf() {
return this.i++
},
toString() {
return this.i++
}
}
console.log(a == 1 && a == 2 && a == 3) // true
2、数组在toString
前先调用join
方法
const a = [1, 2, 3]
a.join = a.shift
console.log(a == 1 && a == 2 && a == 3) // true
3、数据劫持
var i = 1
Object.defineProperty(window, 'a', {
get() {
return i++
}
})
console.log(a === 1 && a === 2 && a === 3) // true
const a = new Proxy(
{ i: 1 },
{
get(target) {
return () => target.i++
}
}
)
console.log(a == 1 && a == 2 && a == 3) // true