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

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

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


当前回答

这是@Jeff的答案*的反转版本,其中使用隐藏字符(U+115F、U+1160或U+3164)创建类似于1、2和3的变量。

变量a=1;变量ᅠ1=a;变量ᅠ2=a;变量ᅠ3=a;console.log(a==ᅠ1和a==ᅠ2&&a(&&a)==ᅠ3 );

*这个答案可以通过使用零宽度非接合(U+200C)和零宽度接合(U+200D)来简化。这两个字符都允许在标识符内,但不能在开头:

变量a=1;变量a‌ = 2.变量a‍ = 3.console.log(a==1&a‌ == 2&&a(&&a)‍ == 3);/****变量a=1;var a\u200c=2;var a\u200d=3;console.log(a==1&&a\u200c==2&&a\u200d==3);****/

其他技巧也可以使用相同的思想,例如使用Unicode变体选择器创建看起来完全相同的变量(a︀ = 1.一︁ = 2.一︀ == 1和a︁ == 2; // 真)。

其他回答

没有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);

它可以在全局范围内使用以下方法完成。对于nodejs,在下面的代码中使用global而不是window。

var值=0;Object.defineProperty(窗口,“a”{获取:函数(){返回++val;}});如果(a==1&&a==2&&a==3){console.log(“是”);}

这个答案通过定义getter来检索变量,从而滥用了全局范围在执行上下文中提供的隐式变量。

使用符号的ECMAScript 6答案:

const a = {value: 1};
a[Symbol.toPrimitive] = function() { return this.value++ };
console.log((a == 1 && a == 2 && a == 3));

由于==的用法,JavaScript应该强制a接近第二个操作数(本例中为1、2、3)。但是,在JavaScript尝试自己计算强制之前,它会尝试调用Symbol.toPrimitive。如果您提供Symbol.toPrimitive,JavaScript将使用函数返回的值。如果没有,JavaScript将调用valueOf。

相同,但不同,但仍然相同(可以多次“测试”):

常量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对象类型方程的工作原理开始的。

我认为这是实现它的最小代码:

i=0,a={valueOf:()=>++i}如果(a==1&&a==2&&a==3){console.log('Mind===Blown');}

创建具有自定义值Of的虚拟对象,该值在每次调用时递增全局变量i。23个字符!