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

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

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


当前回答

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

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

其他回答

使用代理:

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

与大多数其他答案一样,这只适用于松散的等式检查(==),因为严格的等式检查不执行代理可以拦截的类型强制。

这也可以使用一系列自重写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(“是的,这是可能的。”);}})();

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

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

面试规则一;永远不要说不可能。

不需要隐藏角色的诡计。

窗口__定义Getter__('a',函数(){if(类型i!=='number'){//在全局命名空间中定义i,以便在运行此函数后不会丢失i=0;}返回++i;});如果(a==1&&a==2&&a==3){console.log(“哦,亲爱的,我们做了什么?”);}

使用符号的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。