主持人注意:请抵制编辑代码或删除此通知的冲动。空白模式可能是问题的一部分,因此不应进行不必要的篡改。如果您处于“空白是无关紧要的”阵营,您应该能够接受代码。
在JavaScript中,(a==1&&a==2&&a==3)是否有可能求值为真?
这是一家大型科技公司提出的面试问题。事情发生在两周前,但我仍在努力寻找答案。我知道我们在日常工作中从未编写过这样的代码,但我很好奇。
主持人注意:请抵制编辑代码或删除此通知的冲动。空白模式可能是问题的一部分,因此不应进行不必要的篡改。如果您处于“空白是无关紧要的”阵营,您应该能够接受代码。
在JavaScript中,(a==1&&a==2&&a==3)是否有可能求值为真?
这是一家大型科技公司提出的面试问题。事情发生在两周前,但我仍在努力寻找答案。我知道我们在日常工作中从未编写过这样的代码,但我很好奇。
当前回答
这是另一种变体,使用数组弹出所需的任何值。
常量a={n: [3,2,1],toString:函数(){return a.n.pop();}}如果(a==1&&a==2&&a==3){console.log(“是”);}
其他回答
或者,您可以为其使用一个类,为检查使用一个实例。
函数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!');}
没有getters或valueOf的示例:
a=[1,2,3];a.join=a.shift;console.log(a==1&&a==2&&a==3);
这之所以有效,是因为==调用toString,它为数组调用.join。
另一种解决方案,使用Symbol.toPrimitive,它是ES6等价于String/valueOf:
设i=0;让a={[Symbol.toPrimitive]:()=>++i};console.log(a==1&&a==2&&a==3);
这是可能的!
变量i=0;具有({获取a(){返回++i;}}) {如果(a==1&&a==2&&a==3)console.log(“wohoo”);}
这在with语句中使用getter,让一个求值为三个不同的值。
…这仍然不意味着这应该在实际代码中使用。。。
更糟糕的是,使用==也可以使用此技巧。
变量i=0;具有({获取a(){返回++i;}}) {如果(a!==a)console.log(“是的,这是打印的。”);}
这在变量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。在列表中添加越来越多的内容会降低命中率。
正如我们已经知道的,松散相等运算符(==)的秘密将尝试将这两个值转换为公共类型。因此,将调用一些函数。
ToPrimitive(A)尝试将其对象参数转换为原语值,通过调用A.toString和A.valueOf的不同序列方法对A。
与其他使用Symbol.toPrimitive、.toString、.valueOf from integer的答案一样。我建议使用这样的array.pop数组。让a={array:[3,2,1],toString:()=>a.array.pop()};如果(a==1&&a==2&&a==3){console.log(“Hello World!”);}
通过这种方式,我们可以处理这样的文本
让a={array:[“World”,“Hello”],toString:()=>.array.pop()};如果(a==“你好”&&a==”世界“){console.log(“Hello World!”);}