主持人说明: 请拒绝编辑代码或删除此通知的冲动。空白模式可能是问题的一部分,因此不应该被不必要地篡改。如果您在“空白无关紧要”阵营,您应该能够接受原样。
有可能吗? (a== 1 && a ==2 && a==3)
可以评估 true
在JavaScript?
这是一家大型科技公司提出的面试问题。它发生在两周前,但我仍在努力寻找答案。我知道我们从未在日常工作中写过这样的代码,但我很好奇。
主持人说明: 请拒绝编辑代码或删除此通知的冲动。空白模式可能是问题的一部分,因此不应该被不必要地篡改。如果您在“空白无关紧要”阵营,您应该能够接受原样。
有可能吗? (a== 1 && a ==2 && a==3)
可以评估 true
在JavaScript?
这是一家大型科技公司提出的面试问题。它发生在两周前,但我仍在努力寻找答案。我知道我们从未在日常工作中写过这样的代码,但我很好奇。
如果你利用 怎么样 ==
作品,你可以简单地用自定义创建一个对象 toString
(要么 valueOf
)函数改变每次使用它返回的内容,使其满足所有三个条件。
const a = {
i: 1,
toString: function () {
return a.i++;
}
}
if(a == 1 && a == 2 && a == 3) {
console.log('Hello World!');
}
其工作原因是由于使用了松散的等式运算符。当使用松散相等时,如果其中一个操作数的类型与另一个不同,则引擎将尝试将一个操作数转换为另一个。如果左侧是对象而右侧是数字,它将尝试通过首次调用将对象转换为数字 valueOf
如果它是可调用的,并且失败了,它将调用 toString
。我用了 toString
在这种情况下,仅仅是因为它是我想到的, valueOf
会更有意义。如果我改为从中返回一个字符串 toString
然后,引擎会尝试将字符串转换为给出相同最终结果的数字,但路径稍长。
我无法抗拒 - 其他答案无疑是正确的,但你真的无法超越以下代码:
var aᅠ = 1;
var a = 2;
var ᅠa = 3;
if(aᅠ==1 && a== 2 &&ᅠa==3) {
console.log("Why hello there!")
}
请注意中的奇怪间距 if
声明(我从你的问题中复制)。它是半角度Hangul(对于那些不熟悉的人来说是韩语),它是一个Unicode空格字符,ECMA脚本不将其解释为空格字符 - 这意味着它是标识符的有效字符。因此,有三个完全不同的变量,一个是在a之后的Hangul,一个是在它之前,最后一个只是a。用空间替换空间 _
为了便于阅读,相同的代码如下所示:
var a_ = 1;
var a = 2;
var _a = 3;
if(a_==1 && a== 2 &&_a==3) {
console.log("Why hello there!")
}
查看 对Mathias的变量名称验证器进行验证。如果这个奇怪的间距实际上包含在他们的问题中,我确信这是对这种答案的暗示。
不要这样做。认真。
编辑:我已经注意到了(尽管不允许启动变量) 零宽度木匠 和 零宽度非连接器 变量名中也允许使用字符 - 请参阅 用零宽度字符模糊JavaScript - 优点和缺点?。
这将如下所示:
var a= 1;
var a= 2; //one zero-width character
var a= 3; //two zero-width characters (or you can use the other one)
if(a==1&&a==2&&a==3) {
console.log("Why hello there!")
}
有可能的!
var i = 0;
with({
get a() {
return ++i;
}
}) {
if (a == 1 && a == 2 && a == 3)
console.log("wohoo");
}
这使用了一个内部的getter with
声明让 a
评估三个不同的值。
...这仍然不意味着应该在实际代码中使用...
没有getter或valueOf的示例:
a = [1,2,3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3);
这是因为 ==
所调用 toString
哪个叫 .join
对于阵列。
使用另一个解决方案 Symbol.toPrimitive
这是ES6的等价物 toString/valueOf
:
let a = {[Symbol.toPrimitive]: ((i) => () => ++i) (0)};
console.log(a == 1 && a == 2 && a == 3);
如果询问是否可能(不是必须),它可以要求“a”返回一个随机数。如果它顺序生成1,2和3就是如此。
with({
get a() {
return Math.floor(Math.random()*4);
}
}){
for(var i=0;i<1000;i++){
if (a == 1 && a == 2 && a == 3){
console.log("after " + (i+1) + " trials, it becomes true finally!!!");
break;
}
}
}
如果没有正则表达式就无法做任何事情:
var a = {
r: /\d/g,
valueOf: function(){
return this.r.exec(123)[0]
}
}
if (a == 1 && a == 2 && a == 3) {
console.log("!")
}
它的工作原因是自定义 valueOf
当Object与原语(如Number)比较时调用的方法。主要技巧是 a.valueOf
每次都会返回新值,因为它正在调用 exec
用正则表达式 g
标志,导致更新 lastIndex
每次找到匹配时的正则表达式所以第一次 this.r.lastIndex == 0
, 它匹配 1
和更新 lastIndex
: this.r.lastIndex == 1
,所以下次正则表达式会匹配 2
等等。
可以使用全局范围中的以下内容来完成。对于 nodejs
使用 global
代替 window
在下面的代码中。
var val = 0;
Object.defineProperty(window, 'a', {
get: function() {
return ++val;
}
});
if (a == 1 && a == 2 && a == 3) {
console.log('yay');
}
此答案通过定义用于检索变量的getter来滥用执行上下文中的全局作用域提供的隐式变量。
这在变量的情况下是可能的 a
被2个网络工作者通过SharedArrayBuffer以及一些主要脚本访问。可能性很低,但是当代码编译为机器代码时,Web工作者可能会更新变量 a
恰逢其时的条件 a==1
, a==2
和 a==3
很满意。
这可以是Web工作者和JavaScript中的SharedArrayBuffer提供的多线程环境中的竞争条件示例。
以下是上面的基本实现:
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)
worker.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')
})
modifier.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
。添加越来越多的列表会降低击中的可能性。
使用一系列自覆盖吸气剂也可以实现这一点:
(这类似于jontro的解决方案,但不需要计数器变量。)
(() => {
"use strict";
Object.defineProperty(this, "a", {
"get": () => {
Object.defineProperty(this, "a", {
"get": () => {
Object.defineProperty(this, "a", {
"get": () => {
return 3;
}
});
return 2;
},
configurable: true
});
return 1;
},
configurable: true
});
if (a == 1 && a == 2 && a == 3) {
document.body.append("Yes, it’s possible.");
}
})();