Javascript (a== 1 && a ==2 && a==3) 可以评估为真吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/48270127/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can (a== 1 && a ==2 && a==3) ever evaluate to true?
提问by Dimpu Aravind Buddha
Moderator note:Please resist the urge to edit the code or remove this notice. The pattern of whitespace may be part of the question and therefore should not be tampered with unnecessarily. If you are in the "whitespace is insignificant" camp, you should be able to accept the code as is.
版主注意:请抵制编辑代码或删除此通知的冲动。空白模式可能是问题的一部分,因此不应不必要地篡改。如果您在“空白无关紧要”的阵营中,您应该能够按原样接受代码。
Is it ever possible that (a== 1 && a ==2 && a==3)could evaluate to truein JavaScript?
是否有可能在 JavaScript 中(a== 1 && a ==2 && a==3)评估为true?
This is an interview question asked by a major tech company. It happened two weeks back, but I'm still trying to find the answer. I know we never write such code in our day-to-day job, but I'm curious.
这是一家大型科技公司提出的面试问题。它发生在两周前,但我仍在努力寻找答案。我知道我们在日常工作中从来没有写过这样的代码,但我很好奇。
回答by Kevin B
If you take advantage of how ==works, you could simply create an object with a custom toString(or valueOf) function that changes what it returns each time it is used such that it satisfies all three conditions.
如果你趁如何==工作,你可以简单地创建一个自定义的对象toString(或valueOf改变它使用它,使得它满足所有这三个条件,每次返回)功能。
const a = {
i: 1,
toString: function () {
return a.i++;
}
}
if(a == 1 && a == 2 && a == 3) {
console.log('Hello World!');
}
The reason this works is due to the use of the loose equality operator. When using loose equality, if one of the operands is of a different type than the other, the engine will attempt to convert one to the other. In the case of an object on the left and a number on the right, it will attempt to convert the object to a number by first calling valueOfif it is callable, and failing that, it will call toString. I used toStringin this case simply because it's what came to mind, valueOfwould make more sense. If I instead returned a string from toString, the engine would have then attempted to convert the string to a number giving us the same end result, though with a slightly longer path.
这样做的原因是由于使用了松散相等运算符。使用松散相等时,如果一个操作数的类型与另一个不同,引擎将尝试将一个转换为另一个。在左边的对象和右边的数字的情况下,valueOf如果它是可调用的,它将尝试通过首先调用将对象转换为数字,如果失败,它将调用toString. 我toString在这种情况下使用它只是因为它是我想到的,valueOf会更有意义。如果我改为从 返回一个字符串toString,引擎就会尝试将该字符串转换为一个数字,从而得到相同的最终结果,尽管路径稍长。
回答by Jeff
I couldn't resist - the other answers are undoubtedly true, but you really can't walk past the following code:
我无法抗拒 - 其他答案无疑是正确的,但您真的无法跳过以下代码:
var a? = 1;
var a = 2;
var ?a = 3;
if(a?==1 && a== 2 &&?a==3) {
console.log("Why hello there!")
}
Note the weird spacing in the ifstatement (that I copied from your question). It is the half-width Hangul (that's Korean for those not familiar) which is an Unicode space character that is not interpreted by ECMA script as a space character - this means that it is a valid character for an identifier. Therefore there are three completely different variables, one with the Hangul after the a, one with it before and the last one with just a. Replacing the space with _for readability, the same code would look like this:
注意if语句中奇怪的间距(我从你的问题中复制的)。它是半角韩文(对于那些不熟悉的人来说是韩语),它是一个 Unicode 空格字符,ECMA 脚本不会将其解释为空格字符 - 这意味着它是标识符的有效字符。因此,存在三个完全不同的变量,一个在 a 之后是韩文,一个是在 a 之前,最后一个是 a。将空格替换_为可读性,相同的代码如下所示:
var a_ = 1;
var a = 2;
var _a = 3;
if(a_==1 && a== 2 &&_a==3) {
console.log("Why hello there!")
}
Check out the validation on Mathias' variable name validator. If that weird spacing was actually included in their question, I feel sure that it's a hint for this kind of answer.
查看Mathias 的变量名验证器上的验证。如果他们的问题中确实包含了那个奇怪的间距,我相信这是对这种答案的暗示。
Don't do this. Seriously.
不要这样做。严重地。
Edit: It has come to my attention that (although not allowed to start a variable) the Zero-width joinerand Zero-width non-joinercharacters are also permitted in variable names - see Obfuscating JavaScript with zero-width characters - pros and cons?.
编辑:我注意到(尽管不允许开始变量)零宽度连接符和零宽度非连接符字符也允许在变量名称中使用 - 请参阅使用零宽度字符混淆 JavaScript - 优缺点? .
This would look like the following:
这将如下所示:
var a= 1;
var a?= 2; //one zero-width character
var a??= 3; //two zero-width characters (or you can use the other one)
if(a==1&&a?==2&&a??==3) {
console.log("Why hello there!")
}
回答by Jonas Wilms
IT IS POSSIBLE!
有可能的!
var i = 0;
with({
get a() {
return ++i;
}
}) {
if (a == 1 && a == 2 && a == 3)
console.log("wohoo");
}
This uses a getter inside of a withstatement to let aevaluate to three different values.
这在with语句中使用 getter来a评估三个不同的值。
... this still does not mean this should be used in real code...
......这仍然并不意味着这应该在实际代码中使用......
Even worse, this trick will also work with the use of ===.
更糟糕的是,这个技巧也适用于===.
var i = 0;
with({
get a() {
return ++i;
}
}) {
if (a !== a)
console.log("yep, this is printed.");
}
回答by georg
Example without getters or valueOf:
没有 getter 或 valueOf 的示例:
a = [1,2,3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3);
This works because ==invokes toStringwhich calls .joinfor Arrays.
这是有效的,因为==调用toString它调用.join数组。
Another solution, using Symbol.toPrimitivewhich is an ES6 equivalent of toString/valueOf:
另一种解决方案,使用Symbol.toPrimitiveES6 等效于toString/valueOf:
let i = 0;
let a = { [Symbol.toPrimitive]: () => ++i };
console.log(a == 1 && a == 2 && a == 3);
回答by ocomfd
If it is asked if it is possible (not MUST), it can ask "a" to return a random number. It would be true if it generates 1, 2, and 3 sequentially.
如果询问是否可能(不是必须),它可以询问“a”返回一个随机数。如果它依次生成 1、2 和 3,则为真。
with({
get a() {
return Math.floor(Math.random()*4);
}
}){
for(var i=0;i<1000;i++){
if (a == 1 && a == 2 && a == 3){
console.log("after " + (i+1) + " trials, it becomes true finally!!!");
break;
}
}
}
回答by Kos
When you can't do anything without regular expressions:
当没有正则表达式你什么也做不了时:
var a = {
r: /\d/g,
valueOf: function(){
return this.r.exec(123)[0]
}
}
if (a == 1 && a == 2 && a == 3) {
console.log("!")
}
It works because of custom valueOfmethod that is called when Object compared with primitive (such as Number). Main trick is that a.valueOfreturns new value every time because it's calling execon regular expression with gflag, which causing updating lastIndexof that regular expression every time match is found. So first time this.r.lastIndex == 0, it matches 1and updates lastIndex: this.r.lastIndex == 1, so next time regex will match 2and so on.
它之所以起作用valueOf,是因为在 Object 与原始类型(例如 Number)进行比较时会调用自定义方法。主要技巧是a.valueOf每次都返回新值,因为它调用exec带有g标志的正则表达式,这导致lastIndex每次找到匹配项时都会更新该正则表达式。所以第一次this.r.lastIndex == 0,它匹配1并更新lastIndex: this.r.lastIndex == 1,所以下次正则表达式将匹配2等等。
回答by jontro
It can be accomplished using the following in the global scope. For nodejsuse globalinstead of windowin the code below.
可以在全局范围内使用以下内容来完成。为了nodejs使用global,而不是window在下面的代码。
var val = 0;
Object.defineProperty(window, 'a', {
get: function() {
return ++val;
}
});
if (a == 1 && a == 2 && a == 3) {
console.log('yay');
}
This answer abuses the implicit variables provided by the global scope in the execution context by defining a getter to retrieve the variable.
该答案通过定义一个 getter 来检索变量,从而滥用了执行上下文中全局作用域提供的隐式变量。
回答by mehulmpt
This is possible in case of variable abeing accessed by, say 2 web workers through a SharedArrayBuffer as well as some main script. The possibility is low, but it is possible that when the code is compiled to machine code, the web workers update the variable ajust in time so the conditions a==1, a==2and a==3are satisfied.
这在变量a被访问的情况下是可能的,比如 2 个网络工作者通过 SharedArrayBuffer 以及一些主脚本。的可能性较低,但有可能的是,当代码被编译成机器代码,网络工作者更新变量a只是在时间上的条件a==1,a==2并a==3得到满足。
This can be an example of race condition in multi-threaded environment provided by web workers and SharedArrayBuffer in JavaScript.
这可以是 Web Worker 和 JavaScript 中的 SharedArrayBuffer 提供的多线程环境中的竞争条件示例。
Here is the basic implementation of above:
下面是上面的基本实现:
main.js
主文件
// Main Thread
const worker = new Worker('worker.js')
const modifiers = [new Worker('modifier.js'), new Worker('modifier.js')] // Let's use 2 workers
const sab = new SharedArrayBuffer(1)
modifiers.forEach(m => m.postMessage(sab))
worker.postMessage(sab)
worker.js
工人.js
let array
Object.defineProperty(self, 'a', {
get() {
return array[0]
}
});
addEventListener('message', ({data}) => {
array = new Uint8Array(data)
let count = 0
do {
var res = a == 1 && a == 2 && a == 3
++count
} while(res == false) // just for clarity. !res is fine
console.log(`It happened after ${count} iterations`)
console.log('You should\'ve never seen this')
})
modifier.js
修改器.js
addEventListener('message' , ({data}) => {
setInterval( () => {
new Uint8Array(data)[0] = Math.floor(Math.random()*3) + 1
})
})
On my MacBook Air, it happens after around 10 billion iterations on the first attempt:
在我的 MacBook Air 上,它在第一次尝试大约 100 亿次迭代后发生:
Second attempt:
第二次尝试:
As I said, the chances will be low, but given enough time, it'll hit the condition.
正如我所说,机会会很低,但如果有足够的时间,它会达到条件。
Tip: If it takes too long on your system. Try only a == 1 && a == 2and change Math.random()*3to Math.random()*2. Adding more and more to list drops the chance of hitting.
提示:如果您的系统花费的时间太长。仅尝试a == 1 && a == 2并更改Math.random()*3为Math.random()*2。添加越来越多的列表会降低命中的机会。
回答by Patrick Dark
This is also possible using a series of self-overwriting getters:
这也可以使用一系列自覆盖 getter:
(This is similar to jontro's solution, but doesn't require a counter variable.)
(这类似于 jontro 的解决方案,但不需要计数器变量。)
(() => {
"use strict";
Object.defineProperty(this, "a", {
"get": () => {
Object.defineProperty(this, "a", {
"get": () => {
Object.defineProperty(this, "a", {
"get": () => {
return 3;
}
});
return 2;
},
configurable: true
});
return 1;
},
configurable: true
});
if (a == 1 && a == 2 && a == 3) {
document.body.append("Yes, it's possible.");
}
})();
回答by Nina Scholz
Alternatively, you could use a class for it and an instance for the check.
或者,您可以为它使用一个类和一个用于检查的实例。
function A() {
var value = 0;
this.valueOf = function () { return ++value; };
}
var a = new A;
if (a == 1 && a == 2 && a == 3) {
console.log('bingo!');
}
EDIT
编辑
Using ES6 classes it would look like this
使用 ES6 类,它看起来像这样
class A {
constructor() {
this.value = 0;
this.valueOf();
}
valueOf() {
return this.value++;
};
}
let a = new A;
if (a == 1 && a == 2 && a == 3) {
console.log('bingo!');
}


