(a ==1 && a== 2 && a==3)结果是否为true
最近在查资料的时候发现了一个有趣的帖子:
https://stackoverflow.com/questions/48270127/can-a-1-a-2-a-3-ever-evaluate-to-true
内容是帖主在一个大型IT公司面试时遇到的奇怪面试题,题目是这样的:
在JavaScript中,(a ==1 && a== 2 && a==3)可能被判断为 true 吗?
贴主当时回答了“不可能”,然后面试就没有然后了……贴主表示两个星期来自己都没有弄明白这个问题的解法,于是才来发帖求助。
…………
……
恩,对于这个问题,我这类渣渣看了之后也是一脸懵逼的。a作为一个变量,怎么可能同时等于1又等于2还等于3呢……所以我很快就放弃了思考直接往下看大佬们的解答。
最高票答案
const a = {
i: 1,
toString: function () {
return a.i++;
}
}
if(a == 1 && a == 2 && a == 3) {
console.log('Hello World!');
}
是不是有点懵,我也一样,让我们慢慢来看这个代码……
我们的思路是,如何让a在用==
运算符和其他数值进行比较时,那一瞬间a的值和右边的数值一样。
所以我们首先要明白JavaScript中==
运算符的机制,使用==
进行比较时,若两边的参数类型不一致,就会尝试将左边的参数类型转换为与右边相同。而在这段代码中,a是一个对象,右边与a进行比较的参数则是数字,于是会首先尝试调用valueOf
方法,如果失败,则会继续尝试调用toString
方法。
知道了这个原理就可以来搞事情了,就像这段代码里一样,直接重写了a对象的toString
方法,让它返回a对象的i属性,之后i属性自增1。
于是输出结果当然就是:
Hello World!
看完后我只能说:“还有这种操作!”
另外也可以直接重写valueOf
方法来实现,不过这种操作属于奇技淫巧,纯粹用于解答这个面试问题,拓宽思路,正常开发时还是最好不要这样重写valueOf
……
还有这种操作?!
等等,这个帖子下面还有更多其他解答,让我们来看看……
var aᅠ = 1;
var a = 2;
var ᅠa = 3;
if(aᅠ==1 && a== 2 &&ᅠa==3) {
console.log("Why hello there!")
}
这是什么操作?!没错,如果你仔细观察原题目,会发现语句里面有两个奇怪的空格间距。
那真的是空格吗?如果是空格的话,编译时会忽略掉,这三个仍然是同一个变量,最后的表达式的结果当然也是false。
不过,如果你像给出这个答案的答主一样博闻广见,也许会想到这个答案,这个间距其实是半宽度韩文,一个Unicode编码中的空格字符,但是ECMAScript并不将其解释为空格,所以aᅠ
、a
和ᅠa
其实是不同的对象……
那结果当然就是true啦~
还有这种操作???!
var a = 1;
var a = 2;
var а = 3;
if(a == 1 && a == 2 && а == 3) {
console.log("Why hello there!")
}
恩,这段代码看上去似乎是不可能在控制台打印出东西的……因为这次没有什么奇怪的间距了……
等等,中间那个a
好像有点奇怪?好吧,其实这三个a
真不是同一个字符。
a
——正常的拉丁字母小写aa
——全角下的拉丁字母小写aа
——西里尔字母的小写a
恩……所以这仨也不是同一个变量,if判断的最后结果也就是true。
还有这种操作???!!!
var a = 9;
if(a==1 && a== 2 && a==3)
{
console.log("Yes, it is possible!:sunglasses:");
}
function if(){return true;}
等等!怎么可能可以重写if
,关键词不是不能重写吗,我怕是学了假的JavaScript。
天真,看了上面的几个答案后难道还认为这个if
真的就是if
吗?没错……这其实是一个自定义的函数,名字是if
,虽然看起来好像和关键词长一个样了,但实际上……这个if
后面有一个隐藏的字符,这是Unicode编码中的零宽度字符(U+200C,维基参考零宽不连字),所以这样就不跟关键词的if
冲突啦。
然后这个自定义函数不论三七二十一直接返回个true,问题就解决了~
结尾
其实后面这种障眼法多少有些抬杠的感觉,但是很有趣嘛就分享出来了2333,这个帖子还有一些有趣和高大上到我看不懂的答案,可以自己去看看,不失为写代码之间的调味剂。