Are you sure that (a == 1 && a == 2 && a == 3) cannot be true?

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 , ifand 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 avariables, you can also fake three 1, 2, 3variables

const a = 1
const1 = a
const2 = a
const3 = 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 == 3are 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中使用==对两个值进行比较时,会进行如下操作:

  1. 将两个被比较的值转换为相同的类型。
  2. 转换后(等式的一边或两边都可能被转换)再进行值的比较。

比较的规则如下表(mdn

从表中可以得到几点信息为了让(a == 1),a只有这几种:

  1. a类型为String,并且可转换为数字1('1' == 1 => true
  2. a类型为Boolean,并且可转换为数字1 (true == 1 => true)
  3. a类型为Object,通过转换机制后,可转换为数字1 (请看下文

对象转原始类型的"转换机制"

规则1和2没有什么特殊的地方,我们来看看3:

对象转原始类型,会调用内置的[ToPrimitive]函数,逻辑大致如下:

  1. 如果有Symbol.toPrimitive方法,优先调用再返回,否则进行2。
  2. 调用valueOf,如果可以转换为原始类型,则返回,否则进行3。
  3. 调用toString,如果可以转换为原始类型,则返回,否则进行4。
  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

当然也可以利用valueOftoString

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('前端胖头鱼') // 前端胖头鱼
}

复制代码

最后

希望能一直给大家分享实用、基础、进阶的知识点,一起早早下班,快乐摸鱼。

期待你在掘金关注我:前端胖头鱼,也可以在公众号里找到我:前端胖头鱼

Guess you like

Origin juejin.im/post/7079936779914051615