如题,如何让 a==1&&a==2&&a==3 成立?
相信大家看到这样的问题就会很头疼,这该怎么实现呢?但是架不住某些面试官的高频提问,迫不得已寻找解决方案。
步入正题
一、利用 == 中的隐式类型转换
首先要清楚 == 运算符中都发生了什么
js调用==进行比较时,不同与===,双等号会触发类型转换,进行比较的事实上不是原始值,而是**toString()的返回值,所以我们可以从原型方法toString()**上做一点手脚:
let a = {
toString(){
return 'toString'
}
}
if(a == 'toString'){
console.log('toString 方法被重写')
}
可以看到可以重写,那现在只需要让 a 调用 toString() 方法的时候去返回一个自增的变量,可以这样做:
let a = {
i:0,
toString(){
return ++this.i;
}
}
if(a == 1 && a == 2 && a == 3){
console.log('条件成立')
}
可以看到是没问题的:
但是这样还是远远不够的,面试官:还有其他的方法吗?
二、利用数据劫持 Object.defineProperty 来实现
我们都知道 Vue2.x 的双向数据绑定是利用 Object.definProperty 来实现的
利用同样思路,我们可以在条件判断获取 a 的时候去做数据劫持,返回一个自增的数字来实现:
let i = 0;
Object.defineProperty(window, 'a', {
get(){
return ++i;
}
})
if(a == 1 && a == 2 && a == 3){
console.log('条件成立')
}
可以看到条件还是成立的:
那有的人可能就有点疑问了,为什么要 return ++i 呢?不能直接 return ++a 吗?
我们来试一下:
可以看到浏览器给我们报了一个栈溢出的错误,原因是这样的
直接 return ++a 的话,浏览器肯定要先获取到 a 的值,再自增,获取 a 的值肯定会被 **Object.defineProperty 劫持到,**所以就造成了一个无限循环的递归,肯定会造成栈溢出。
三、还可以利用 toString() 方法
let a = [1, 2, 3];
a.toString = a.shift;
if (a == 1 && a == 2 && a == 3) {
console.log('条件成立');
}
将数组 a 的 toString() 方法重写,替换为 shift 方法,shift 方法是删除数组头部元素,并返回,这样的话每次调用 a 的 toString 方法就会删除第一个元素并返回
第一次做判断删除并返回 1
第二次删除并返回 2
....
以达成目的。
还有几种方法也都是通过数据劫持或者重写原型上的 toString 方法或 valueOf 方法,这里就不一一列举了。
如果你觉得这篇文章对你有帮助不妨评论留言分享,后续会有更多关于前端方面的知识和技巧。