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

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

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


当前回答

如果没有正则表达式就无法执行任何操作:

变量a={r: /\d/g,valueOf:函数(){返回此.r.exec(123)[0]}}如果(a==1&&a==2&&a==3){console.log(“!”)}

它之所以有效,是因为当Object与基元(如Number)进行比较时调用了自定义valueOf方法。主要技巧是,a.valueOf每次都会返回新值,因为它使用g标志对正则表达式调用exec,这会导致每次找到匹配项时更新该正则表达式的lastIndex。所以第一次this.r.lastIndex==0时,它匹配1并更新lastIndex:this.r.lastIndex==1,所以下次regex将匹配2,依此类推。

其他回答

这也可以使用一系列自重写getter:

(这类似于jontro的解决方案,但不需要计数器变量。)

(() => {“使用严格”;Object.defineProperty(this,“a”{“获取”:()=>{Object.defineProperty(this,“a”{“获取”:()=>{Object.defineProperty(this,“a”{“获取”:()=>{返回3;}});返回2;},可配置:真});返回1;},可配置:真});如果(a==1&&a==2&&a==3){document.body.append(“是的,这是可能的。”);}})();

正如我们已经知道的,松散相等运算符(==)的秘密将尝试将这两个值转换为公共类型。因此,将调用一些函数。

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!”);}

我无法抗拒——其他答案毫无疑问是正确的,但你真的无法通过以下代码:

变量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(“你好!”)}

我没有看到这个答案已经发布了,所以我也会把这个加入到混合中。这与Jeff使用半宽朝鲜文空格的回答类似。

变量a=1;变量a = 2.varа=3;如果(a==1&&a == 2 && а == 3) {console.log(“你好!”)}

你可能会注意到与第二个略有不同,但第一个和第三个与肉眼完全相同。所有3个字符都是不同的:

a-拉丁文小写aa - 全宽拉丁文小写Aа-西里尔文小写A

通用术语是“同字形”:看起来相同的不同unicode字符。通常很难找到三个完全无法区分的,但在某些情况下,你可能会很幸运。A、 Α、А和Ꭺ 会更好地工作(拉丁字母A、希腊字母Alpha、西里尔字母A和切罗基字母A);不幸的是,希腊语和切罗基语小写字母与拉丁字母A:α,ꭺ, 因此对上面的片段没有帮助)。

有一整类的同字形攻击,最常见的是假域名(例如,wikipediа.org(西里尔文)vs wikipedia.org(拉丁语)),但它也可以在代码中出现;通常被称为隐藏(正如一篇评论中所提到的,[隐藏]问题现在在PPCG上已不再是话题,但在过去,这类问题会成为一种挑战)。我使用这个网站来查找用于这个答案的同字形。

这是另一种变体,使用数组弹出所需的任何值。

常量a={n: [3,2,1],toString:函数(){return a.n.pop();}}如果(a==1&&a==2&&a==3){console.log(“是”);}