冰镇

千万世界中的一个小小埃希镇

0%

Langs | (a == 1 && a == 2 && a == 3)能否为true?

今天在朋友圈看到某大佬转发的关于(a == 1 && a == 2 && a == 3)JavaScript上能否为true文章,觉得特别有趣,于是想了解一波。

某国外哥们在面试的时候被问到这个问题,他的回答是impossible,而面试官的回答是nothing is impossible,然后就没有然后了。

然后这哥们左思右想,决定去StackOverFlow上问问到底有什么方法,原帖在此

JavaScript

拿到这个问题的时候,我们都知道第一反应是,如果a是个普通的变量,那怎么都不可能做到等于1之后马上变成2。(当然,也或许我太菜不知道有没有什么方法)

但是,如果a不是一个对象,那就很多可操作性了。阅读了一下StackOverFlow的原帖,我决定把上面的一些方法都Copy下来讨论一下。

#1: ==的非严格相等特性

MDN的==工作原理里面有提到,对于==的非严格相等比较来说,如果A是Object、B是Number,那么就比较B === ToPrimitive(A)ToPrimitive(A)实际上就是尝试依次调用A.toString()A.valueOf()

那么如果我们在toString()或者valueOf()里面做手脚,自然可以达到上述的效果。

let a = {
  val: 1,
  toString: function () {
    return this.val++
  }
}

console.log(a == 1 && a == 2 && a == 3)

这里亦可将toString改为valueOf

#2: Array.prototype.join()

这里也是利用了==的非严格相等特性,我们上面知道如果类型不一样是会有可能调用toString()的,而数组的toString()是通过调用Array.prototype.join()来获取字符串的。如果我们修改了该函数,那一样可以达到题目效果。

let a = [ 1, 2, 3 ]
a.join = a.shift

console.log(a == 1 && a == 2 && a == 3)

这里利用了shift依次删除数组头部元素。

#3: Symbol.toPrimitive

还是==,上面我们说了比较实际上是B === ToPrimitive(A)。我们直接修改atoPrimitive,也可以达到这样的效果。

let a = { [Symbol.toPrimitive]: ((i) => () => i++)(1) }

console.log(a == 1 && a == 2 && a == 3)

第一行代码看起来或许有点变扭,我一开始也没看懂什么意思。不过,我们知道[Symbol.toPrimitive]是一个函数,这里的代码本质上是做了一个闭包,然后返回一个函数。我们或许可以这样写:

let a = {
  [Symbol.toPrimitive]: (function (i) {
    return function () {
      return i++
    }
  })(1)
}

console.log(a == 1 && a == 2 && a == 3)

#4: get访问器

with ({
  val: 1,
  get a() {
    return this.val++
  }
}) {
  console.log(a == 1 && a == 2 && a == 3)
}

这里利用了get访问器使得a可以直接访问对象里面的val,然后再通过with关键词使得该对象的所有成员都在该作用域下,无需通过对象来访问成员。

当然,with关键词的使用会导致代码无法优化,使得运行效率下降。

Extend: 精度

在阅读这个问题的答案的时候,有一个回答令我眼前一亮,不过这个回答不是针对于使得a == 1 && a == 2 && a == 3true的。代码如下:

let a = 100000000000000000

console.log(a === a + 1 && a === a + 2 && a === a + 3)

这段代码利用了精度的问题,使得上述表达式为真。说实话,我还是第一次看到精度还能这样用。果然还是学识浅薄,果然还是太菜了。

Ruby

看到这个问题的时候,我的第一个反应就是运算符重载。不过题目给的是JavaScript,也没想出什么方法。不过Ruby就爽了,毕竟,一切皆为对象。什么运算符什么都是虚的,本来就是方法嘛,我对方法修改就好了嘛。

class Fixnum < Integer
  def ==(o)
    true
  end
end

a = 1
puts a == 1 && a == 2 && a == 3

然后美滋滋地输出了true

当然,Ruby还有别的奇怪的方法,有空再来补充。


如果你有别的好的方法,不妨交流一下!(逃

土豪与Zhenly通道