主持人注意:请抵制编辑代码或删除此通知的冲动。空白模式可能是问题的一部分,因此不应进行不必要的篡改。如果您处于“空白是无关紧要的”阵营,您应该能够接受代码。
在JavaScript中,(a==1&&a==2&&a==3)是否有可能求值为真?
这是一家大型科技公司提出的面试问题。事情发生在两周前,但我仍在努力寻找答案。我知道我们在日常工作中从未编写过这样的代码,但我很好奇。
主持人注意:请抵制编辑代码或删除此通知的冲动。空白模式可能是问题的一部分,因此不应进行不必要的篡改。如果您处于“空白是无关紧要的”阵营,您应该能够接受代码。
在JavaScript中,(a==1&&a==2&&a==3)是否有可能求值为真?
这是一家大型科技公司提出的面试问题。事情发生在两周前,但我仍在努力寻找答案。我知道我们在日常工作中从未编写过这样的代码,但我很好奇。
当前回答
我无法抗拒——其他答案毫无疑问是正确的,但你真的无法通过以下代码:
变量aᅠ = 1.变量a=2;变量ᅠa=3;如果(aᅠ==1&&a==2&&ᅠa==3){console.log(“你好!”)}
注意if语句中奇怪的空格(我从你的问题中复制的)。它是半宽朝鲜文(对于不熟悉的人来说是朝鲜语),它是一个Unicode空格字符,ECMA脚本不会将其解释为空格字符-这意味着它是标识符的有效字符。因此,有三个完全不同的变量,一个是a后面的朝鲜文,一个在a之前,最后一个只有a。为了可读性,将空格替换为_,相同的代码如下所示:
变量a_=1;变量a=2;var_a=3;如果(a_==1&&a==2&&_a==3){console.log(“你好!”)}
查看Mathias变量名验证器的验证。如果这个奇怪的间距真的包含在他们的问题中,我确信这是一个暗示,暗示了这种答案。
不要这样做。认真地
编辑:我注意到(虽然不允许启动变量)变量名称中也允许使用零宽度连接符和零宽度非连接符-请参阅用零宽度字符混淆JavaScript-利弊?。
如下所示:
变量a=1;变量a= 2; //一个零宽度字符变量a= 3; //两个零宽度字符(也可以使用另一个)如果(a==1&a==2&&a(&&a)==3) {console.log(“你好!”)}
其他回答
相同,但不同,但仍然相同(可以多次“测试”):
常量a={valueOf:()=>this.n=(this.n||0)%3+1}如果(a==1&&a==2&&a==3){console.log(“Hello World!”);}如果(a==1&&a==2&&a==3){console.log(“Hello World!”);}
我的想法是从Number对象类型方程的工作原理开始的。
如果询问是否可能(不是必须),它可以要求“a”返回一个随机数。如果它依次生成1、2和3,则为真。
具有({获取a(){return Math.floor(Math.random()*4);}}){对于(var i=0;i<1000;i++){如果(a==1&&a==2&&a==3){console.log(“在”+(i+1)+“试用之后,它终于变成了真的!!!”);打破}}}
这在变量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!');}
通过在类声明中重写valueOf,可以执行以下操作:
class Thing {
constructor() {
this.value = 1;
}
valueOf() {
return this.value++;
}
}
const a = new Thing();
if(a == 1 && a == 2 && a == 3) {
console.log(a);
}
发生的情况是在每个比较运算符中调用valueOf。第一次,a等于1,第二次,a将等于2,依此类推,因为每次调用valueOf时,a的值都会递增。
因此,console.log将激发并输出(在我的终端中)Thing:{value:4},表示条件为真。