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

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

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


当前回答

使用代理:

var a = new Proxy({ i: 0 }, {
    get: (target, name) => name === Symbol.toPrimitive ? () => ++target.i : target[name],
});
console.log(a == 1 && a == 2 && a == 3);

代理基本上假装是目标对象(第一个参数),但拦截目标对象上的操作(在本例中是“获取属性”操作),以便有机会执行默认对象行为以外的其他操作。在这种情况下,对when==强制其类型调用“get property”操作,以便将其与每个数字进行比较。发生这种情况:

我们创建一个目标对象{i:0},其中i属性是我们的计数器我们为目标对象创建代理,并将其分配给对于每个a==比较,a的类型都被强制为基元值这种类型强制导致在内部调用[Symbol.toPrimitive]()Proxy使用“get handler”拦截获取[Symbol.toPrimitive]函数代理的“获取处理程序”检查正在获取的属性是否为Symbol.toPrimitive,在这种情况下,它会递增,然后从目标对象返回计数器:++target.i。如果正在检索不同的属性,我们只需返回默认属性值target[name]

So:

var a = ...; // a.valueOf == target.i == 0
a == 1 && // a == ++target.i == 1
a == 2 && // a == ++target.i == 2
a == 3    // a == ++target.i == 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!');}

我没有看到这个答案已经发布了,所以我也会把这个加入到混合中。这与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={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,依此类推。

好了,又一个发电机黑客:

常量值=函数*(){设i=0;而(真)产量++i;}();Object.defineProperty(this,“a”{获取(){return value.next().value;}});如果(a==1&&a==2&&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对象类型方程的工作原理开始的。