想要解决这个问题,首先需要考虑两个数据在使用 == 比较时的类型转换
== 进行比较的时候,如果左右两边的数据类型不同
则先转换为相同的数据类型,然后再进行比较值是否相等
分为以下几种情况:
+ {} == {} 两个对象比较,是比较堆内存的地址 => false
+ null == undefined => true
+ NaN == NaN => false
+ [12] == '12' 对象和字符串的比较是把对象用 toString() 方法转换为字符串后在进行比较
+ 其他情况比较的时候,都是转换为数字进行比较 (前提是数据类型不同)
- 对象转数字:先把对象转换为字符串,然后在转成数字
- 字符串转数字:只要出现一个非数字字符,结果就是NaN
- 布尔转数字: true => 1 false => 0
- null转数字: => 0
- undefined转数字: => NaN
所以想要 a==1 && a==2 成立,那么a可以为一个引用类型,然后将a转换数字类型
方案一
因为 将对象转数字时,是先把对象转换为字符串,然后在转成数字
又知道 对象原型上的 toString() 方法只能用于监测数据类型 => Object.prototype.toString.call(a) 所以如果 a 为一个对象那么 a==1 的比较就转换成 => "[object Object]" ==1 的比较,进而转换成 => NaN == 1 => false
既然改变不了会调用 toString()方法,那么就可以给 a 对象添加一个私有的同名 toString 方法,这样对象转数字时默认调用 toString 时,就不会去 Object 原型上找,直接掉用自己私有的 toString 这样就可以在自己添加的 toString 方法上随心所欲改造成想要的样子
var a = {
num:0,
// 给a添加私有的toString方法
toString() {
return ++this.num
}
}
第一次比较使用 toString 时,结果返回值为1,a.num的值为1
然后比较 a==2,再次调用toString,返回的结果就是2。
console.log(a==1 && a==2) // true
方案二
利用比较时会默认调用 toString 这个特点,可以将 toString'偷梁换柱'成需要的内置方法;数组有个 shift 方法,可以删除数组的第一项并返回第一项的值,且原数组改变,那么就可以将数组 shift 方法名字,赋值给 toString;在,在默认使用 toString 时,本质是走了 shift 的逻辑
let b = [1,2,3]
// 偷梁换柱
b.toString = b.shift
console.log(b==1&&b==2&&b==3) // true
方案三
valueOf() 方法可以返回指定对象的原始值。
var c = {
num:0,
valueOf() {
return ++this.num
}
}
第一次比较时,直接返回1,结果成立,此时c.num的值为1
然后比较a==2,再次返回c的结果为2
console.log(c==1 && c==2) // true
方案四
Object.defineProperty 方法 直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
它有一个 get 方法,每次只要获取监视对象的属性值就会触发,利用这个特性也可以实现
let num = 0
Object.defineProperty(window,'d',{
get() {
return ++num
}
})
在第一次比较 d==1 时,会触发get方法并返回1,结果成立。此时d的值为1,当再次d==2比较时又触发get方法返回2,结果成立
console.log(d==1&&d==2&&d==3) // true
本文使用 mdnice 排版