(仅为自己学习)
前两天看到了一道很有趣的题目,题目大意为:JS 环境下,如何让 a == 1 && a == 2 && a == 3 这个表达式返回 true ? 。
这道题目乍看之下似乎不太可能,因为在正常情况下,一个变量的值如果没有手动修改,在一个表达式中是不会变化的。当时我也冥思苦想很久,甚至一度怀疑这道题目的答案就是 不能。直到最近开始刷掘金发现了这个题的答案,奇奇怪怪的知识又增加了。
其中常见的答案是
const a = {
i: 1,
toString: function () {
return a.i++;
}
}
if (a == 1 && a == 2 && a == 3) {
console.log('Hello World!');
}
原来这道题目的考点原来是 JS 获取一个变量所需要做的操作以及其中一些细节。在 JS 中有 === 和 == 两种方式来判断两个变量是否相等。对 JS 稍有了解的人都知道,=== 是严格相等,不仅需要两个变量的值相同,还需要类型也相同,而 == 则是宽松下的相等,只需要值相同就能够判断相等,宽松相等是严格相等的子集。
null == undefined // true
null === undefined // false
1 == '1' // true
1 === '1' // false
大家可以自行补一下JS 特有的,变量宽松相等判断的各种情况。大致可以得到三种情况:
- 操作数 A 类型为 String,并且调用 +A 的结果与 B 严格相等
- 操作数 A 类型为 Boolean,并且调用 +A 的结果与 B 严格相等
- 操作数 A 类型为 Object,并且调用 toString 或者 ValueOf 返回的结果与 B 严格相等
所以上面的答案就是新建了一个对象 a ,并有 toString 方法,当 JS 引擎每次读取 a 的值的时候,发现需要进行宽松判断一个对象和一个数字之间的结果,对于对象就会执行这里的 toString 方法,在这个方法内部,我们每次增加另一个变量的值并返回,就能够在这条表达式中使得 a 的结果有不同的值。
同理,换一种写法,a 为 Object ,使用 valueOf 也是可以完成目标的:
const a = {
i: 1,
valueOf () {
return this.i++;
}
}
if (a == 1 && a == 2 && a == 3) {
console.log('Hello World!');
}
大家都可以尝试哈。