主持人注意:请抵制编辑代码或删除此通知的冲动。空白模式可能是问题的一部分,因此不应进行不必要的篡改。如果您处于“空白是无关紧要的”阵营,您应该能够接受代码。
在JavaScript中,(a==1&&a==2&&a==3)是否有可能求值为真?
这是一家大型科技公司提出的面试问题。事情发生在两周前,但我仍在努力寻找答案。我知道我们在日常工作中从未编写过这样的代码,但我很好奇。
主持人注意:请抵制编辑代码或删除此通知的冲动。空白模式可能是问题的一部分,因此不应进行不必要的篡改。如果您处于“空白是无关紧要的”阵营,您应该能够接受代码。
在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!”);}
其他回答
这是可能的!
变量i=0;具有({获取a(){返回++i;}}) {如果(a==1&&a==2&&a==3)console.log(“wohoo”);}
这在with语句中使用getter,让一个求值为三个不同的值。
…这仍然不意味着这应该在实际代码中使用。。。
更糟糕的是,使用==也可以使用此技巧。
变量i=0;具有({获取a(){返回++i;}}) {如果(a!==a)console.log(“是的,这是打印的。”);}
通过在类声明中重写valueOf,可以执行以下操作:
class Thing {
constructor() {
this.value = 1;
}
valueOf() {
return this.value++;
}
}
const a = new Thing();
if(a == 1 && a == 2 && a == 3) {
console.log(a);
}
发生的情况是在每个比较运算符中调用valueOf。第一次,a等于1,第二次,a将等于2,依此类推,因为每次调用valueOf时,a的值都会递增。
因此,console.log将激发并输出(在我的终端中)Thing:{value:4},表示条件为真。
如果利用==的工作原理,您可以简单地创建一个带有自定义toString(或valueOf)函数的对象,该函数在每次使用时都会更改其返回的内容,以使其满足所有三个条件。
常量a={i: 1中,toString:函数(){返回a.i++;}}如果(a==1&&a==2&&a==3){console.log(“Hello World!”);}
这之所以有效,是因为使用了松散的相等运算符。使用松散相等时,如果其中一个操作数的类型与另一个不同,则引擎将尝试将其中一个转换为另一个。在左边是一个对象,右边是一个数字的情况下,它将尝试通过首先调用valueOf(如果它是可调用的)将对象转换为一个数字,否则,它将调用toString。在这种情况下,我习惯使用String,因为这是我想到的,valueOf更有意义。如果我从toString返回一个字符串,那么引擎将尝试将该字符串转换为一个数字,从而得到相同的最终结果,尽管路径稍长。
正如我们已经知道的,松散相等运算符(==)的秘密将尝试将这两个值转换为公共类型。因此,将调用一些函数。
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={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,依此类推。