Maybe you and I have never met, but it is very likely that we will meet each other late, I am a front-end fat head fish
foreword
Recently I encountered a very interesting interview question: Is it possible to make a(a== 1 && a ==2 && a==3)
return in JavaScript true
?
To tell you the truth, when I first saw this question, I looked at the interviewer with this look: Are you kidding me? Can you respect me? After 10 years of cerebral thrombosis, I can't ask this thing,
But looking at his "cheap smile", a feeling that you must not be able to answer, I don't think this matter is easy...
I'm kneeling on my knees
Let's first take a look at a few peculiar solutions, regardless of what the interviewer's intention is and what knowledge is specifically examined.
Solution 1: Hidden characters + if
const if = () => !0
const a = 9
if(a == 1 && a == 2 && a == 3)
{
console.log('前端胖头鱼') // 前端胖头鱼
}
复制代码
Seeing is false
I think you are like me at this time, you are seriously doubting that you are a fake front end , if
and can you be rewritten? a明明是9却可以等于1、2、3
?
Don't worry, this is actually a blind method, it's just a trick to blind our eyes, please see the picture below
真相大白
: There is a hidden character after if, which essentially declares a function that returns true no matter what is input, and the following code block has nothing to do with this function, it will be executed no matter what!!!
{
console.log('前端胖头鱼') // 前端胖头鱼
}
复制代码
So by constructing a code block that seems to rewrite the if, it seems that the problem is really realized, which is really annoying! ! !
Solution 2: Hidden character + a variable
With the above experience, you will not be surprised by the next solution.
const aᅠ = 1
const a = 2
const ᅠa = 3
if (aᅠ == 1 && a == 2 && ᅠa == 3) {
console.log('前端胖头鱼') // 前端胖头鱼
}
复制代码
Solution 3: Hidden characters + numeric variables
Since you can fake three a
variables, you can also fake three 1
, 2
, 3
variables
const a = 1
const ᅠ1 = a
const ᅠ2 = a
const ᅠ3 = a
if (a == ᅠ1 && a == ᅠ2 && a == ᅠ3) {
console.log('前端胖头鱼') // 前端胖头鱼
}
复制代码
Daqian world, as expected, seeing is false! ! !
Another strange solution
The above several solutions a == 1 && a == 2 && a == 3
are true
, but they are blind tricks, everyone just smiles! I'm going to be serious next time...
解法4:“with”
MDN上映入眼帘的是一个警告,仿佛他的存在就是个错误,我也从来没有在实际工作中用过他,但他却可以用来解决这个题目。
let i = 1
with ({
get a() {
return i++
}
}) {
if (a == 1 && a == 2 && a == 3) {
console.log('前端胖头鱼')
}
}
复制代码
聪明的你甚至都不用我解释代码啥意思了。
隐式转换成解题的关键
上面给出的4种解法多少有点歪门邪道的意思,为了让面试官死心,接下来的才是正解之道,而JS中的隐式转换规则大概也是出这道题的初衷。
隐式转换部分规则
JS中使用==
对两个值进行比较时,会进行如下操作:
- 将两个被比较的值转换为相同的类型。
- 转换后(等式的一边或两边都可能被转换)再进行值的比较。
比较的规则如下表(mdn)
从表中可以得到几点信息为了让(a == 1
),a只有这几种:
- a类型为String,并且可转换为数字1(
'1' == 1 => true
) - a类型为Boolean,并且可转换为数字1 (
true == 1 => true
) - a类型为Object,通过
转换机制
后,可转换为数字1 (请看下文
)
对象转原始类型的"转换机制"
规则1和2没有什么特殊的地方,我们来看看3:
对象转原始类型,会调用内置的[ToPrimitive]函数,逻辑大致如下:
- 如果有Symbol.toPrimitive方法,优先调用再返回,否则进行2。
- 调用valueOf,如果可以转换为原始类型,则返回,否则进行3。
- 调用toString,如果可以转换为原始类型,则返回,否则进行4。
- 如果都没有返回原始类型,会报错。
const obj = {
value: 1,
valueOf() {
return 2
},
toString() {
return '3'
},
[Symbol.toPrimitive]() {
return 4
}
}
obj == 4 // true
// 您可以将Symbol.toPrimitive、toString、valueOf分别注释掉验证转换规则
复制代码
解法5: Symbol.toPrimitive
我们可以利用隐式转换规则3完成题目(看完答案你就知道为什么啦!
)
const a = {
i: 1,
[Symbol.toPrimitive]() {
return this.i++
}
}
// 每次进行a == xxx时都会先经过Symbol.toPrimitive函数,自然也就可以实现a依次递增的效果
if (a == 1 && a == 2 && a == 3) {
console.log('前端胖头鱼') // 前端胖头鱼
}
复制代码
解法6: valueOf vs toString
当然也可以利用valueOf
和toString
let a = {
i: 1,
// valueOf替换成toString效果是一样的
// toString
valueOf() {
return this.i++
}
}
if (a == 1 && a == 2 && a == 3) {
console.log('前端胖头鱼') // 前端胖头鱼
}
复制代码
解法7:Array && join
数组对象在进行隐式转换时,同样符合规则3,只是在toString
时还会调用join
方法。所以也可以从这里下手
let a = [1, 2, 3]
a.join = a.shift
if (a == 1 && a == 2 && a == 3) {
console.log('前端胖头鱼') // 前端胖头鱼
}
复制代码
数据劫持亦是一条出路
通过隐式转换我们做出了3种让a == 1 && a == 2 && a == 3
返回true的方案,聪明的你一定想到另一种思路,数据劫持
,伟大的Vue就曾使用数据劫持赢得了千万开发者的芳心,我们也试试用它来解决这道面试题
解法8:Object.defineProperty
通过劫持window
对象,每次读取a
属性时,都给_a 增加1
let _a = 1
Object.defineProperty(window, 'a', {
get() {
return _a++
}
})
if (a == 1 && a == 2 && a == 3) {
console.log('前端胖头鱼') // 前端胖头鱼
}
复制代码
解法9:Proxy
当然还有另一种劫持数据的方式,Vue3也是将响应式原理中的数据劫持Object.defineProperty
换成了Proxy
let a = new Proxy({ i: 1 }, {
get(target) {
return () => target.i++
}
})
if (a == 1 && a == 2 && a == 3) {
console.log('前端胖头鱼') // 前端胖头鱼
}
复制代码
最后
希望能一直给大家分享实用、基础、进阶的知识点,一起早早下班,快乐摸鱼。
期待你在掘金关注我:前端胖头鱼,也可以在公众号里找到我:前端胖头鱼。