a == 1 && a == 2 && a == 3
题目很简单,只要让if
语句中的判断条件成立即可。
if (a == 1 && a == 2 && a == 3) {
console.log('win!!!');
}
首先分析题目,题目的意思只要我们能够让a
同时与1,2,3
相等的话,那么此时就成功了。很显然此时a
并不能只是一个普通的值,因为如果a
只是一个普通值的话,它是没有办法做到同时与三个值相同的。这条思路行不通,我们需要再想想其它的方法。
其实我们可以从==
运算符下手,提到 ==
我们可以联想到隐式类型转换,那么我们可不可以通过隐式类型转换来处理这道题呢,分析一下。
既然牵扯到隐式类型转换,无非就存在下面几种转换的规则:
toPrimitive()
:Symbol.toPrimitive => valueOf => toString
将值转为原始值(原始类型)
toNumber()
:Symbol.toPrimitive => valueOf => toString
将值转为数字
toString()
:Symbol.toPrimitive => toString => valueOf
将值转为字符串
熟悉完规则后,我们再来看看题目。虽然a
不能是原始值,但是我们可以将a
设置为一个对象的形式,当对象与数值进行==
运算的时候,是会执行toPrimitive
规则的隐式转换逻辑。
var a = {
step: 0,
toString() {
return ++this.step;
}
}
if (a == 1 && a == 2 && a == 3) {
console.log('win');
}
a === 1 && a === 2 && a === 3
那么如果替换稍微变换的话,那么我们又该如何操作呢?刚刚是==
运算符,是存在隐式转换的问题。而如果此时是===
严格相等的话,那么就不存在隐式转换的问题。那么我们又该如何设计呢?
既然现在的情况是不存在隐式转换的问题,那么我们就没有办法通过valueof/toString
方法去解决这个问题了,因为此时是不会调用toString、valueof
方法。
我们再次分析if(a === 1 && a === 2 && a === 3)
题目,当在执行a === 1
的时候,程序是要去访问a
的值,这样才能够进行对比。既然存在访问a
这个操作,那么我们是不是可以通过数据劫持的方式来对a
值进行处理呢?
if (a === 1 && a === 2 && a === 3) {
console.log('win!!!');
}
如果用到数据劫持的话,我们可以使用Object.defineProperty()方法来处理。但是defineProperty是需要在对象上定义属性,而我们的a属性放在哪里比较合适呢?当然是存放在window对象上比较合适。所以我们可以这样去做:
var step = 0;
Object.defineProperty(window, 'a', {
get () {
return ++step;
}
});
if (a === 1 && a === 2 && a === 3) {
console.log('win!!!');
}
再次改变一下题目,如果题目换为下面的方式,又该如何操作呢?
if (obj.a === 1 && obj.a === 2 && obj.a === 3) {
console.log('win!!!');
}
很简单,也是数据劫持。但是我们可以不用defineProperty
对象定义属性的方式去做,我们可以直接在对象中通过语法糖的方式进行处理。比如说像下面一样去做:
get、set
函数是直接可以写在对象内部中去。
var obj = {
_step: 0,
get a() {
return ++ this._step;
}
}
if (obj.a === 1 && obj.a === 2 && obj.a === 3) {
console.log('win!!!');
}