主持人注意:请抵制编辑代码或删除此通知的冲动。空白模式可能是问题的一部分,因此不应进行不必要的篡改。如果您处于“空白是无关紧要的”阵营,您应该能够接受代码。

在JavaScript中,(a==1&&a==2&&a==3)是否有可能求值为真?

这是一家大型科技公司提出的面试问题。事情发生在两周前,但我仍在努力寻找答案。我知道我们在日常工作中从未编写过这样的代码,但我很好奇。


当前回答

或者,您可以为其使用一个类,为检查使用一个实例。

函数A(){var值=0;this.valueOf=函数(){return++value;};}var a=新a;如果(a==1&&a==2&&a==3){console.log('bingo!');}

EDIT

使用ES6类时,情况如下

A类{构造器(){this.value=0;this.valueOf();}值Of(){返回this.value++;};}设a=新a;如果(a==1&&a==2&&a==3){console.log('bingo!');}

其他回答

这在变量a被访问的情况下是可能的,例如,2个web工作人员通过SharedArray Buffer以及一些主脚本进行访问。可能性很低,但当代码被编译为机器代码时,网络工作人员可能会及时更新变量a,从而满足条件a==1、a==2和a==3。

这可以是web工作者和JavaScript中的SharedArray Buffer提供的多线程环境中的竞争条件的一个示例。

以下是上述的基本实现:

main.js

// Main Thread

const worker = new Worker('worker.js')
const modifiers = [new Worker('modifier.js'), new Worker('modifier.js')] // Let's use 2 workers
const sab = new SharedArrayBuffer(1)

modifiers.forEach(m => m.postMessage(sab))
worker.postMessage(sab)

工人.js

let array

Object.defineProperty(self, 'a', {
  get() {
    return array[0]
  }
});

addEventListener('message', ({data}) => {
    array = new Uint8Array(data)
    let count = 0
    do {
        var res = a == 1 && a == 2 && a == 3
        ++count
    } while(res == false) // just for clarity. !res is fine
    console.log(`It happened after ${count} iterations`)
    console.log('You should\'ve never seen this')
})

修改器.js

addEventListener('message' , ({data}) => {
    setInterval( () => {
        new Uint8Array(data)[0] = Math.floor(Math.random()*3) + 1
    })
})

在我的MacBook Air上,第一次尝试大约100亿次迭代后会发生这种情况:

第二次尝试:

正如我所说,机会很低,但如果有足够的时间,它会达到条件。

提示:如果系统花费的时间太长。只尝试a==1&&a==2,然后将Math.random()*3更改为Math.random()*2。在列表中添加越来越多的内容会降低命中率。

或者,您可以为其使用一个类,为检查使用一个实例。

函数A(){var值=0;this.valueOf=函数(){return++value;};}var a=新a;如果(a==1&&a==2&&a==3){console.log('bingo!');}

EDIT

使用ES6类时,情况如下

A类{构造器(){this.value=0;this.valueOf();}值Of(){返回this.value++;};}设a=新a;如果(a==1&&a==2&&a==3){console.log('bingo!');}

老实说,不管有没有一种方法可以评估它的真实性(正如其他人所展示的,有多种方法),我要寻找的答案是,作为一个已经进行了数百次面试的人来说,大致如下:

“嗯,也许是的,在一些奇怪的情况下,这些情况对我来说不是很明显……但如果我在真实的代码中遇到了这种情况,我会使用常见的调试技术来弄清楚它是如何以及为什么在做它正在做的事情,然后立即重构代码以避免这种情况……但更重要的是:我绝对不会在一开始就写代码,因为这就是复杂代码的定义,我努力不写复杂代码”。

我想有些面试官会对提出一个显然是非常棘手的问题感到愤怒,但我不介意有意见的开发人员,特别是当他们能够用合理的想法来支持这一点,并将我的问题融入到一个关于自己的有意义的陈述中时。

它可以在全局范围内使用以下方法完成。对于nodejs,在下面的代码中使用global而不是window。

var值=0;Object.defineProperty(窗口,“a”{获取:函数(){返回++val;}});如果(a==1&&a==2&&a==3){console.log(“是”);}

这个答案通过定义getter来检索变量,从而滥用了全局范围在执行上下文中提供的隐式变量。

这是@Jeff的答案*的反转版本,其中使用隐藏字符(U+115F、U+1160或U+3164)创建类似于1、2和3的变量。

变量a=1;变量ᅠ1=a;变量ᅠ2=a;变量ᅠ3=a;console.log(a==ᅠ1和a==ᅠ2&&a(&&a)==ᅠ3 );

*这个答案可以通过使用零宽度非接合(U+200C)和零宽度接合(U+200D)来简化。这两个字符都允许在标识符内,但不能在开头:

变量a=1;变量a‌ = 2.变量a‍ = 3.console.log(a==1&a‌ == 2&&a(&&a)‍ == 3);/****变量a=1;var a\u200c=2;var a\u200d=3;console.log(a==1&&a\u200c==2&&a\u200d==3);****/

其他技巧也可以使用相同的思想,例如使用Unicode变体选择器创建看起来完全相同的变量(a︀ = 1.一︁ = 2.一︀ == 1和a︁ == 2; // 真)。