今天群里发了一个问题:怎么让(a == 1 && a == 2 && a == 3)为true,群友给出了几个答案,感觉挺有意思的,在这里分享一下。
思路1、隐式转换
首先想到的就是利用 == 时会出现隐式转换来解决这个问题,复杂类型数据进行隐式转换成number时会先使用valueOf()获取原始值,如果原始值不是number类型则会使用toString()转换为字符串,此时就有两个解决方案:valueOf与toString
valueOf
const a = {
n : 1,
valueOf:() => {
return a.n++
}
}
console.log(a == 1 && a == 2 && a == 3); //true
toString
const a = [1,2,3];
a.toString = a.shift;
console.log(a == 1 && a == 2 && a == 3); //true
思路2、Symbol.toPrimitive
当对象被转化为原始值时会触发Symbol.toPrimitive函数,此时可以对a进行修改
let n = 1;
const a = {
[Symbol.toPrimitive](hint) {
return n++;
},
};
console.log(a == 1 && a == 2 && a == 3); //true
思路3、Object.definedProperty
在a进行比较的时候我们可以利用Object.definedProperty进行数据劫持来实现相应功能,此时(a === 1 && a ===2 && a === 3)也为true
let n = 1;
Object.definedProperty(window, 'a',{
get: function(){
return n++;
}
})
console.log(a == 1 && a ==2 && a == 3);
以上就是让(a == 1 && a == 2 && a == 3)为true的几个方法了,在总结这几个方法的时候也遇到了几个问题
1、Proxy
想到用Object.definedProperty来处理时也想到了Proxy,但是在实际操作时发与Object.definedProperty相比proxy需要一个实例来劫持window的属性,而又不能将这个实例设为window,所以只能实现(proxy.a == 1 && proxy.a ==2 && proxy.a == 3)
2、用Symbol.toPrimitive时发现了这个问题
查阅资料之后了解到Symbol.toPrimitive是一个内置的 Symbol 值,是作为对象的函数值属性存在,它的执行上下文里没有n这个在a对象内的值,所以需要将n放在外面让Symbol.toPrimitive获取到。