题目
如何让下面的条件为真?
if (a == 1 && a == 2 && a == 3) {
console.log('OK');
}
解决思路
首先,一个值要能 ==1 2 3,那么他绝对不可能是基本数据类型(number,string,boolean,null,undefined,symbol,bigint);
那么我们基本确定a是一个引用数据类型,笼统的说a是一个对象,再看 == 这个比较运算会在两边数据类型不同时,触发隐式的类型转换,那么问题就可以简化为:让a进行三次类型转换且分别转换为1 2 3;
对象转换成数字会触发三个隐藏副本( [Symbol.toPrimitive] / valueOf / toString ),这里我选取第一个,所以我们的第一个解决方案出炉了!
方案一:
let a = {
arr:[1,2,3],
[Symbol.toPrimitive]: function(hint){
return this.arr.shift()
}
}
if (a == 1 && a == 2 && a == 3) {
console.log('OK');
}
除了借用类型转换,还有没有别的办法呢?当然有了。想一想,我们在 a == 1 这个语句执行时做了什么?第一步就是找到VO里变量a实际的值对吧?那么我们是不是可以借助一个叫数据劫持的东西做点文章?ok,那么第二个方案就出现了。
方案二:
+ 全局下声明的变量是window的一个属性
+ 用Object.defineProperty数据劫持(VUE2 也是靠这招实现的响应式数据)
let i = 0;
Object.defineProperty(window, 'a', {
get() {
return ++i;
}
});
到此为止,我只想到了2种方式,也欢迎大佬补充