(a== 1 & & a ==2 && a==3) 可以计算为真吗?

Can (a== 1 && a ==2 && a==3) ever evaluate to true?

提问人:Dimpu Aravind Buddha 提问时间:1/16/2018 最后编辑:Brad LarsonDimpu Aravind Buddha 更新时间:7/22/2023 访问量:417473

问:

想改进这篇文章吗?提供此问题的详细答案,包括引文和解释为什么您的答案是正确的。没有足够细节的答案可能会被编辑或删除。

主持人注:请抵制编辑代码或删除此通知的冲动。空格模式可能是问题的一部分,因此不应被不必要地篡改。如果你在“空格无关紧要”的阵营中,你应该能够按原样接受代码。

是否有可能在 JavaScript 中进行评估?(a== 1 && a ==2 && a==3)true

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

JavaScript ECMAScript-6

评论

12赞 deceze 1/16/2018
评论不用于扩展讨论;此对话已移至 Chat
123赞 tomsmeding 1/17/2018
对于那些显然投票认为这太宽泛的人来说:这是对 Javascript 的挖掘,说有太多有效的答案吗?
32赞 P.Brian.Mackey 1/18/2018
有些人围坐在一起思考什么是可能的。其他人则将精力集中在他们是否正在为客户构建可行的、商业正确的产品上。IMO,这个问题除了你永远不应该在面试中问这类问题或编写这种代码之外,没有任何实际用处。这就是为什么它应该被关闭。我的意思是,真的,企业是否意识到他们付钱给某人坐下来谈论这些东西?
20赞 Jesse C. Slicer 1/18/2018
看完答案后,这个故事的寓意是:不要在你说的时候使用,有一个禁止非ASCII变量名称的编码标准,以及一个强制执行前两个道德的linting过程。=====
92赞 BoltClock 1/18/2018
主持人注:Stack Overflow 有一段历史,人们用不同的语言回答了相关问题。这些都是试图回答这个问题的尝试,因为它们是一般问题的解决方案,尽管使用不同的语言。请不要将它们标记为“不是答案”。话虽如此,也请不要发布更多不同语言的答案 - 这个问题是特定于 JavaScript 的,正如其他一些答案下的评论所指出的那样,我们喜欢我们的语言特定问题保持这种状态是有原因的。

答:

650赞 Jonas Wilms 1/16/2018 #1

这是可能的!

var i = 0;

with({
  get a() {
    return ++i;
  }
}) {
  if (a == 1 && a == 2 && a == 3)
    console.log("wohoo");
}

这使用语句中的 getter 来计算三个不同的值。witha

...这仍然不意味着应该在实际代码中使用......

更糟糕的是,这个技巧也适用于使用 .===

  var i = 0;

  with({
    get a() {
      return ++i;
    }
  }) {
    if (a !== a)
      console.log("yep, this is printed.");
  }

评论

69赞 Pointy 1/16/2018
是的,我在尝试同样的事情:)因此,面试中的正确答案是,“这不会在我的代码中发生,因为我从不使用。with
8赞 jfriend00 1/16/2018
@Pointy - 而且,我在不允许的严格模式下编程。with
7赞 J_rite 1/16/2018
@Pointy在公认的答案中,他们会做一些类似的事情,而没有这样它就可以发生with
2赞 Jonas Wilms 1/16/2018
@jorrit没有人会使用 .并阻止接受的答案=====
4赞 wortwart 1/17/2018
@JonasW。很多人仍在使用,但从那以后我就没见过了......好吧,实际上从来没有在JS文档之外说“请不要使用它”。无论如何,一个不错的解决方案。==with
3493赞 Kevin B 1/16/2018 #2

如果您利用 == 的工作原理,您可以简单地创建一个带有自定义(或)函数的对象,该函数在每次使用时都会更改它返回的内容,以便它满足所有三个条件。toStringvalueOf

const a = {
  i: 1,
  toString: function () {
    return a.i++;
  }
}

if(a == 1 && a == 2 && a == 3) {
  console.log('Hello World!');
}


这样做的原因是使用了松散相等运算符。使用松散相等时,如果其中一个操作数的类型与另一个操作数的类型不同,则引擎将尝试将一个操作数转换为另一个操作数。如果左边是对象,右边是数字,它将尝试将对象转换为数字,方法是首先调用它是否可调用,否则,它将调用 。在这种情况下,我使用只是因为它是我想到的,会更有意义。如果我从 返回一个字符串,引擎将尝试将字符串转换为数字,从而为我们提供相同的最终结果,尽管路径稍长。valueOftoStringtoStringvalueOftoString

评论

77赞 Sterling Archer 1/16/2018
你能通过改变隐含操作来实现这一点吗?valueOf()
49赞 Kevin B 1/16/2018
是的,出于同样的原因,valueOf 可以代替 toString
4赞 deceze 1/16/2018
评论不用于扩展讨论;此对话已移至 Chat
16赞 Salman A 1/16/2018
,将首先尝试数字转换,因此稍微好一点。valueOf
7赞 tomsmeding 1/16/2018
@Pureferret等式比较的左侧是一个对象,而不是一个数字。该对象具有 number 属性不会打扰引擎。;)i
196赞 jontro 1/16/2018 #3

可以在全局范围内使用以下方法完成此操作。用于代替在下面的代码中。nodejsglobalwindow

var val = 0;
Object.defineProperty(window, 'a', {
  get: function() {
    return ++val;
  }
});
if (a == 1 && a == 2 && a == 3) {
  console.log('yay');
}

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

评论

0赞 jfriend00 1/16/2018
这假定它似乎不是该属性。如果是一个局部变量(看起来像),那么这将不起作用。athisa
1赞 jontro 1/16/2018
@jfriend00你的意思是,如果你放置了 var a;地方?
0赞 jfriend00 1/16/2018
是的。引用意味着 than 是某处的变量,而不是 的属性。虽然有一个奇怪的地方,比如全局变量,两者都可能是真的,但一般来说,用 or 声明一个变量意味着没有让你像代码假设的那样作为属性访问。所以,你的代码显然是在假设一些奇怪的全局变量。例如,您的代码在 node.js 中不起作用,在函数内部的严格模式下不起作用。您应该指定它起作用的确切情况,并可能解释它起作用的原因。否则,它具有误导性。a == 1athisvar alet athisa
0赞 jontro 1/16/2018
@jfriend00很确定。不确定它是否会与其他已经回答的答案相结合增加更多价值。将更新答案
15赞 Zac Delventhal 1/18/2018
问题是,这个“永远”是真的吗?答案是肯定的,这是它可能为真的场景之一:不是局部变量,而是在全局范围内使用递增的 getter 定义的。a
2157赞 Jeff 1/16/2018 #4

我无法抗拒 - 其他答案无疑是正确的,但你真的无法跳过以下代码:

var aᅠ = 1;
var a = 2;
var ᅠa = 3;
if(aᅠ==1 && a== 2 &&ᅠa==3) {
    console.log("Why hello there!")
}

请注意语句中奇怪的间距(我从您的问题中复制的)。它是半角韩文(对于那些不熟悉的人来说是韩语),它是一个 Unicode 空格字符,不会被 ECMA 脚本解释为空格字符 - 这意味着它是标识符的有效字符。因此,有三个完全不同的变量,一个是 a 之后的韩文,一个是 a 之前的韩文,最后一个是 a。为了便于阅读,将空格替换为相同的代码,如下所示:if_

var a_ = 1;
var a = 2;
var _a = 3;
if(a_==1 && a== 2 &&_a==3) {
    console.log("Why hello there!")
}

查看 Mathias 变量名称验证器上的验证。如果这个奇怪的间距真的包含在他们的问题中,我确信这是对这种答案的暗示。

别这样。认真地。

编辑:我注意到(虽然不允许启动变量)变量名称中也允许使用零宽度连接器和零宽度非连接器字符 - 请参阅使用零宽度字符混淆 JavaScript - 优点和缺点?

这如下所示:

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!")
}

评论

389赞 Baracus 1/16/2018
从原始问题中的奇怪间距来看,我认为这正是面试问题正在寻找的答案——利用看起来像空格的非空格字符。好地方!
22赞 Jeff 1/16/2018
@Baracus 是 RonJohn 注意到他对 Kevin 答案的评论中奇怪的间距,这让我想起了这种(可怕的)技术,所以我不能因为发现它而受到赞誉。不过,我有点惊讶没有人回答这个问题,因为几年前由于某处的一篇博客文章,它在我的工作中流传开来——我有点认为它现在已经是常识了。
110赞 Sanchises 1/16/2018
当然,这是被禁止的标准漏洞,这也适用于面试。[需要引证]
15赞 Holger 1/17/2018
考虑到原始间距,情况可能会更糟,即使用了变量;所以有三个变量(,所以)...var ᅠ2 = 3aᅠᅠ= 1, ᅠ2 = 3, a = 3a␣ = 1, ␣2 = 3, a = 3(a␣==1 && a==␣2 && a==3)
3赞 Jeff 1/18/2018
@AL-zami 中有两个变量中有一个额外的字符,它在屏幕上显示为空格,但被解释为标识符的一部分,这意味着有三个独立的变量 - a、a 和 a - 额外的字符是韩文半角空间。
276赞 ocomfd 1/16/2018 #5

如果询问是否可能(不是必须的),它可以要求“a”返回一个随机数。如果它按顺序生成 1、2 和 3,则为 true。

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;
    }
  }
}

评论

114赞 ESR 1/17/2018
即使我知道其他解决方案,我也会故意给出这个答案,因为它回答了问题,但显然不是他们所追求的。玩愚蠢的游戏,赢取愚蠢的奖品。
3赞 Piyin 1/22/2018
但是,如果需要超过 1000 次试验呢?
13赞 Skeets 1/23/2018
@Piyin 如果超过 1000 次试用,您将赢得奖品!
6赞 Ponkadoodle 1/23/2018
我喜欢这个答案,因为它极端地表明,如果 cpu 的寄存器/缓存在程序运行时受到足够多的宇宙射线的撞击,或者如果故意执行电源故障,使得 if 条件的故障分支实际上不会跳跃,这在任何语言中都是可能的。
1赞 KyleFairns 1/30/2018
最低:1,最高:412。
147赞 Patrick Dark 1/16/2018 #6

这也可以使用一系列自覆盖 getter 来实现:

(这类似于 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.");
    }
})();

评论

64赞 Makyen 1/17/2018
请注意,使用 getter 的方法也适用于 ,而不仅仅是 。=====
0赞 Roy Tinker 1/24/2018
此解决方案依赖于成为箭头函数主体内的全局对象。this
0赞 Patrick Roberts 1/25/2018
@Midnightas我不会将任何其他答案归类为“金字塔代码”。
0赞 Johannes 7/9/2018
请注意,这也适用于任意顺序,不是吗?喜欢?(a == 3 && a == 2 && a == 1)
135赞 Nina Scholz 1/16/2018 #7

或者,您可以为它使用一个类,为检查使用一个实例。

function A() {
    var value = 0;
    this.valueOf = function () { return ++value; };
}

var a = new A;

if (a == 1 && a == 2 && a == 3) {
    console.log('bingo!');
}

编辑

使用 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!');
}

评论

5赞 Dave C 1/18/2018
才刚刚开始?function A() {value = 0;
0赞 Danyal Sandeelo 1/24/2019
valueOf被覆盖,所以当我们比较这个值时,它实际上会增加一个。this method is usually called automatically by JavaScript behind the scenes, and not explicitly in code
74赞 MonkeyZeus 1/17/2018 #8

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

无需隐藏的角色诡计。

window.__defineGetter__( 'a', function(){
    if( typeof i !== 'number' ){
        // define i in the global namespace so that it's not lost after this function runs
        i = 0;
    }
    return ++i;
});

if( a == 1 && a == 2 && a == 3 ){
    console.log( 'Oh dear, what have we done?' );
}

评论

7赞 Jonas Wilms 1/18/2018
哎哟。 其实不是JS语言的一部分,只是一个丑陋的版本。 不是一个函数,这个未声明的太可怕了。似乎仍然值得 40 个赞:/__defineGetter__definePropertytypeofi
6赞 MonkeyZeus 1/18/2018
@JonasW。41 个顶 :-)我知道它已弃用,developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... 但它显然在我的 FireFox v 57.0.4 中执行,所以我选择显示它,而不是因为遗留代码是真实的,不能被忽视。不管丑陋如何,以我的方式声明是一种众所周知/有据可查的行为。也许我只是在PCG的心情̄\_(ツ)_/ ̄中__defineGetter__defineProperty()i
0赞 Piyin 1/10/2023
“面试的第一条规则;永远不要说不可能“,如果一切皆有可能,那么某事就有可能是不可能的,所以前提是假的
0赞 MonkeyZeus 1/11/2023
@Piyin 技术上正确是最糟糕的正确,努力成为“ackchyyuly”的家伙并不是一个受人尊敬的荣誉。在与任何不像你一样迂腐的人打交道时,请记住这一点。“永不言败”是性格的反映,它揭示了你是一个思想封闭还是思想开放的人。这不是一个旨在反映哲学完整性的声明。
0赞 Piyin 1/11/2023
@MonkeyZeus 为什么它是最糟糕的正确类型?这句话是如何揭示这一点的?这不是关于哲学的完整性,而是关于一个错误的前提。
130赞 Draco18s no longer trusts SE 1/17/2018 #9

我没有看到这个答案已经发布,所以我也会把这个答案扔进去。这类似于 Jeff 对半宽韩文空间的回答

var a = 1;
var a = 2;
var а = 3;
if(a == 1 && a == 2 && а == 3) {
    console.log("Why hello there!")
}

您可能会注意到与第二个略有不同,但第一个和第三个与肉眼相同。这 3 个都是不同的角色:

a- 拉丁文小写字母 A - 全宽拉丁文小写字母 A - 西里尔文小写字母 A

а

这方面的通用术语是“同形文字”:看起来相同的不同 Unicode 字符。通常很难获得三个完全无法区分的但在某些情况下,您可能会很幸运。A、Α、А 和 Ꭺ 会更好用(分别是拉丁文 A、希腊文 Alpha、西里尔文 A 和切诺基文 A;不幸的是,希腊文和切诺基文的小写字母与拉丁 :,,因此对上述片段没有帮助)。aα

有一整类的同形文字攻击,最常见的是假域名(例如。 (西里尔文)与(拉丁文)),但它也可以出现在代码中;通常被称为卑鄙(正如评论中提到的,[卑鄙的]问题现在在PPCG上是偏离主题的,但曾经是一种挑战,这些事情会出现)。我使用这个网站来查找用于此答案的同形文字。wikipediа.orgwikipedia.org

评论

19赞 1/17/2018
“细微差异”不是我所说的。
4赞 Draco18s no longer trusts SE 1/17/2018
@hvd 完全取决于您的字体呈现。这就是我所看到的
1赞 Draco18s no longer trusts SE 1/17/2018
@Jake是的,全角拉丁文小写字母 A 并不是最好的同形字形(但大写字母变体令人惊叹)。一般来说,你只需要两个就可以获得预期的效果。
10赞 Salman A 1/19/2018
您还可以使用 unicode 变体选择器 (U+FE00..U+FE0F)。这些都不是 : .再也不用担心差异了。aa︀a︁a︂
15赞 Ben Aubin 1/17/2018 #10

这个使用 defineProperty,有一个很好的副作用导致全局变量!

var _a = 1

Object.defineProperty(this, "a", {
  "get": () => {
    return _a++;
  },
  configurable: true
});

console.log(a)
console.log(a)
console.log(a)

评论

8赞 Nina Scholz 1/17/2018
您可以使用闭包:不需要全局。aget: (a => () => ++a)(0),
13赞 Ben Aubin 1/17/2018
@NinaScholz当然,但我们在这里谈论的是不良做法 - 让我:D
216赞 Kos 1/17/2018 #11

当你没有正则表达式就什么都做不了的时候:

var a = {
  r: /\d/g, 
  valueOf: function(){
    return this.r.exec(123)[0]
  }
}

if (a == 1 && a == 2 && a == 3) {
    console.log("!")
}

它之所以有效,是因为当 Object 与原始(例如 Number)进行比较时调用的自定义 valueOf 方法。主要诀窍是每次都返回新值,因为它调用带有标志的正则表达式,这会导致每次找到匹配项时更新该正则表达式的 lastIndex。所以第一次,它匹配并更新:,所以下次正则表达式会匹配,依此类推。a.valueOfexecgthis.r.lastIndex == 01lastIndexthis.r.lastIndex == 12

评论

22赞 yume_chan 1/17/2018
@Abdillah正则表达式对象将记住它匹配的最后一个索引,则再次调用将从该索引开始搜索。MDN不是很清楚。exec
0赞 Abdillah 1/17/2018
我明白了,所以正则表达式对象记住了状态/索引。谢谢!this.r
0赞 Bergi 1/19/2018
我建议将字符串传递给 though,而不是要字符串化的整数。exec
0赞 Aleksey Solovey 1/29/2018
使用正则表达式,现在你有两个问题
26赞 Gustavo Rodríguez 1/17/2018 #12

实际上,在每种编程语言中,问题第一部分的答案都是“是”。例如,这是在 C/C++ 的情况下:

#define a   (b++)
int b = 1;
if (a ==1 && a== 2 && a==3) {
    std::cout << "Yes, it's possible!" << std::endl;
} else {
    std::cout << "it's impossible!" << std::endl;
}

评论

28赞 Keith Thompson 1/17/2018
我不认为这在每种编程语言中都可能。例如,并非所有语言都有预处理器。就此而言,并非所有语言都使用逻辑“和”。&&
3赞 Donald Duck 1/17/2018
我找到了一种在 PythonC++ 中都有效的方法,它使用运算符重载。
7赞 CAD97 1/17/2018
你可以在 Java 中使用反射和搞砸整数缓存来做到这一点。
8赞 Jason Carr 1/17/2018
不能在不支持突变的语言中做到这一点,例如,在haskell中没有可比性
4赞 Uyghur Lives Matter 1/17/2018
问题是问JavaScript,而不是C++。
40赞 Théophile 1/17/2018 #13

这是另一个变体,使用数组弹出您想要的任何值。

const a = {
  n: [3,2,1],
  toString: function () {
    return a.n.pop();
  }
}

if(a == 1 && a == 2 && a == 3) {
  console.log('Yes');
}

33赞 BaggersIO 1/17/2018 #14

好的,另一个带有生成器的黑客:

const value = function* () {
  let i = 0;
  while(true) yield ++i;
}();

Object.defineProperty(this, 'a', {
  get() {
    return value.next().value;
  }
});

if (a === 1 && a === 2 && a === 3) {
  console.log('yo!');
}

评论

0赞 Cody G 1/24/2018
你说黑客,但我很确定这是生成器的用例...... :)(好吧,除了这依赖于 window 对象)this
67赞 Frank W. Zammetti 1/17/2018 #15

老实说,无论有没有办法评估它是否真实(正如其他人所表明的那样,有多种方法),我正在寻找的答案,作为一个进行过数百次采访的人,将是大致如下:

“嗯,也许是的,在一些奇怪的情况下,这些情况对我来说并不明显......但是如果我在实际代码中遇到这种情况,那么我会使用常见的调试技术来弄清楚它如何以及为什么做它正在做的事情,然后立即重构代码以避免这种情况......但更重要的是:我绝对不会首先编写该代码,因为这是复杂代码的定义,我努力从不编写复杂代码。

我猜有些面试官会因为提出一个显然非常棘手的问题而感到生气,但我不介意那些有意见的开发人员,尤其是当他们能够用理性的思考来支持它,并能将我的问题与关于他们自己的有意义的陈述相吻合时。

评论

13赞 Shammoo 1/17/2018
这个问题(或所有面试问题)可能是测试候选人思考问题的意愿,尤其是那些“明显明显”的问题,比如这个问题。拒绝思考的人,因为他们相信自己“知道”答案,这不是一个好人。
5赞 Frank W. Zammetti 1/17/2018
@Don Hatch 不,如果他们真诚地回答,我不会惩罚他们,特别是如果他们像其他人那样给出了正确的答案......但随后我会要求跟进,尝试探究他们是否认为这是编写代码的好方法。知识渊博并能够提出“正确”的答案只是成为一名优秀开发人员的一部分。对于“专业”开发人员来说,更重要的是编写易于理解和维护的代码,而这些代码通常由能力较弱的开发人员编写。过于聪明的开发人员几乎和无能的 IME 一样糟糕。
17赞 TylerH 1/17/2018
这并不能回答这个问题。
6赞 Jonas Wilms 1/17/2018
这个答案的可悲之处在于,昨天有一位 1rep 用户回答了这个问题,并获得了 2 张反对票,导致他删除了这个问题。
8赞 TylerH 1/19/2018
@JohnColeman问题询问代码如何计算为 true。它首先没有问面试官提出问题的原因。这个答案甚至没有试图解决被问到的问题,而是完全集中在“我会做什么”的版本上,试图猜测面试官的目的是什么。如果这是被问到的问题,那就太宽泛了。因此,这个答案不属于这里或网站上的任何地方。
208赞 mehulmpt 1/17/2018 #16

如果变量被 2 个 Web 工作者通过 SharedArrayBuffer 以及一些主脚本访问,这是可能的。这种可能性很低,但当代码被编译为机器码时,Web Worker 可能会及时更新变量,从而满足条件。aaa==1a==2a==3

这可以是 Web Worker 和 JavaScript 中的 SharedArrayBuffer 提供的多线程环境中的争用条件示例。

以下是上述的基本实现:

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)

工作.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')
})

修饰符.js

addEventListener('message' , ({data}) => {
    setInterval( () => {
        new Uint8Array(data)[0] = Math.floor(Math.random()*3) + 1
    })
})

在我的 MacBook Air 上,第一次尝试时大约需要 100 亿次迭代后,这种情况就会发生:

enter image description here

第二次尝试:

enter image description here

正如我所说,机会会很低,但只要有足够的时间,它就会达到条件。

提示:如果您的系统花费的时间太长。仅尝试并更改为 .将越来越多的内容添加到列表中会降低命中的机会。a == 1 && a == 2Math.random()*3Math.random()*2

评论

52赞 Tom Swirly 1/17/2018
老实说,这是最好的答案。所有其他答案都需要刻意尝试做一些非常不直观的事情。这个答案实际上反映了现实世界中可能发生的事情——竞争条件。
36赞 Graham 1/17/2018
不仅如此,我实际上在现实世界中也看到了这种情况。不是问题中的确切条件,而是在函数开始时检查 (a==1) 和函数后面检查 (a==2),并让代码同时满足这两个条件。仅供参考,我第一次看到这种情况是在汽车发动机控制器中,我们制定了编码标准。第二次是在军用飞机的谷壳和火炬分配器系统中,在我进入公司的第一天,我发现并修复了它,而团队的其他成员仍在讨论这个问题。(荣誉等级:高! :)
42赞 psaxton 1/19/2018
那么,您已经研究过“汽车发动机控制器”和“谷壳和火炬分配器系统”,这些系统是用 javascript 和 Web Worker 编程的?我想我不会再出门了。
15赞 Graham 1/19/2018
@psaxton :)当然不是 - 但我们有共享数据的多线程软件。这是所有多线程软件的反模式,并非特定于 Javascript 或 Web Worker。不管你是用汇编语言、Brainf*ck、Visual BASIC、C 还是 Javascript 编程,如果你在多线程应用程序中使用共享数据来编程,它总是会失败。
4赞 qntm 1/24/2018
我认为这是对@jontro答案的精心包装。
99赞 Eric Duminil 1/17/2018 #17

JavaScript的

一个 == 一个 +1

在 JavaScript 中,没有整数,只有 s,它们被实现为双精度浮点Number

这意味着,如果一个数字足够大,它可以被认为是等于四个连续的整数:a

a = 100000000000000000
if (a == a+1 && a == a+2 && a == a+3){
  console.log("Precision loss!");
}

诚然,这并不完全是面试官所问的(它不适用于),但它不涉及任何隐藏函数或运算符重载的技巧。a=0

其他语言

作为参考,Ruby 和 Python 中有解决方案。稍作修改,在 Java 中也可以。a==1 && a==2 && a==3

红宝石

自定义 :==

class A
  def ==(o)
    true
  end
end

a = A.new

if a == 1 && a == 2 && a == 3
  puts "Don't do this!"
end

或增加:a

def a
  @a ||= 0
  @a += 1
end

if a == 1 && a == 2 && a == 3
  puts "Don't do this!"
end

您可以为新类定义:==

class A:
    def __eq__(self, who_cares):
        return True
a = A()

if a == 1 and a == 2 and a == 3:
    print("Don't do that!")

或者,如果您喜欢冒险,请重新定义整数的值

import ctypes

def deref(addr, typ):
    return ctypes.cast(addr, ctypes.POINTER(typ))

deref(id(2), ctypes.c_int)[6] = 1
deref(id(3), ctypes.c_int)[6] = 1
deref(id(4), ctypes.c_int)[6] = 1

print(1 == 2 == 3 == 4)
# True

它可能会段错误,具体取决于您的系统/解释器。

python 控制台因上述代码而崩溃,因为 or 可能在后台使用。如果您使用不太常见的整数,它可以正常工作:23

>>> import ctypes
>>> 
>>> def deref(addr, typ):
...     return ctypes.cast(addr, ctypes.POINTER(typ))
... 
>>> deref(id(12), ctypes.c_int)[6] = 11
>>> deref(id(13), ctypes.c_int)[6] = 11
>>> deref(id(14), ctypes.c_int)[6] = 11
>>> 
>>> print(11 == 12 == 13 == 14)
True

爪哇岛

可以修改 Java Integer 缓存

package stackoverflow;

import java.lang.reflect.Field;

public class IntegerMess
{
    public static void main(String[] args) throws Exception {
        Field valueField = Integer.class.getDeclaredField("value");
        valueField.setAccessible(true);
        valueField.setInt(1, valueField.getInt(42));
        valueField.setInt(2, valueField.getInt(42));
        valueField.setInt(3, valueField.getInt(42));
        valueField.setAccessible(false);

        Integer a = 42;

        if (a.equals(1) && a.equals(2) && a.equals(3)) {
            System.out.println("Bad idea.");
        }
    }
}

评论

27赞 Eric Duminil 1/18/2018
@c ᴏʟᴅsᴘᴇᴇ:Java、Javascript、potayto、potahto :)已经有足够多的好 JS 答案了。我只是觉得展示如何用其他语言完成它会很有趣,并可能给 JS 开发人员一些想法。
2赞 Eric Duminil 1/18/2018
@c ᴏʟᴅsᴘᴇᴇᴅ:更新了 JS 示例。
1赞 CAD97 1/19/2018
为什么 Java 版本不能(或)兼容?据我了解,自动装箱,应该装箱所有整数。或者这是否为比较打开了装箱?Integer a = 42Integer a = 42; a == 1 && a == 2 && a == 3
0赞 Eric Duminil 1/19/2018
@CAD97:似乎会导致拆箱。但是使用强制自动装箱,所以它有效。感谢您的评论!Integer == intInteger#equals(int)
0赞 Eric Duminil 1/19/2018
@StephanBijzitter:请解释。据我所知,JS中只有,基本上和s差不多。它们可以看起来像整数,你可以像整数一样使用它们,但它们仍然不是整数。我认为 Java/Python/C/Ruby/ 中的整数永远不会成立......Numbersdoublen == n + 1
568赞 4 revsgeorg #18

没有 getter 或 valueOf 的示例:

a = [1,2,3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3);

这之所以有效,是因为调用调用数组。==toString.join

另一种解决方案,使用是 ES6 等价物:Symbol.toPrimitivetoString/valueOf

let i = 0;
let a = { [Symbol.toPrimitive]: () => ++i };

console.log(a == 1 && a == 2 && a == 3);

评论

11赞 Jonas Wilms 1/17/2018
without valueOf井。。。它更间接,但基本上是一回事。
12赞 Alex Pedersen 1/17/2018
我真的很喜欢这个解决方案,因为除了对象自己的连接函数之外,您不会覆盖任何东西,而且它只是一个非常干净且易于阅读的技巧,可以使逻辑评估为真。
29赞 Zac Delventhal 1/18/2018
老实说,我认为这是最好的答案。它不涉及任何异常,只是设置了一些值。即使有基本的JS知识,也很容易理解。干的好。
17赞 Andrew 1/18/2018
这很有意义,几乎感觉很有用。
8赞 GBarroso 1/18/2018
我知道大多数答案都是关于虐待,但这个答案让我完全措手不及。非常聪明,我不知道它确实在内部调用,但它完全有道理。toStringvalueOf.join
43赞 Dirk Vollmar 1/17/2018 #19

如果你遇到这样的面试问题(或者注意到你的代码中有一些同样出乎意料的行为),想想什么样的事情可能会导致乍一看不可能的行为:

  1. 编码:在这种情况下,您正在查看的变量不是您认为的变量。如果您故意使用同形字形或空格字符来弄乱 Unicode,以使变量的名称看起来像另一个变量,则可能会发生这种情况,但编码问题也可能意外引入,例如,当从 Web 复制和粘贴包含意外 Unicode 代码点的代码时(例如,因为内容管理系统进行了一些“自动格式化”,例如替换为 Unicode “LATIN SMALL LIGATURE FL” (U+FB02))。fl

  2. 争用条件:可能会发生争用条件,即代码未按开发人员预期的顺序执行的情况。竞争条件通常发生在多线程代码中,但多线程并不是竞争条件成为可能的必要条件 - 异步性就足够了(不要混淆,异步并不意味着在后台使用多个线程)。

    请注意,因此 JavaScript 也不能仅仅因为它是单线程的而不受竞争条件的影响。请参阅此处,了解一个简单的单线程(但异步)示例。然而,在单个语句的上下文中,竞争条件在 JavaScript 中很难达到。

    带有 Web Worker 的 JavaScript 有点不同,因为您可以有多个线程。@mehulmpt向我们展示了使用 Web Worker 的出色概念验证

  3. 副作用:相等比较操作的副作用(不必像此处的示例那样明显,通常副作用非常微妙)。

这类问题可能出现在许多编程语言中,而不仅仅是 JavaScript,因此我们在这里没有看到经典的 JavaScript WTF 之一1.

当然,面试问题和这里的样本看起来都非常做作。但它们很好地提醒了我们:

  • 副作用可能会变得非常令人讨厌,并且精心设计的程序应该没有不必要的副作用。
  • 多线程和可变状态可能会有问题。
  • 不正确地进行字符编码和字符串处理可能会导致令人讨厌的错误。

1 例如,您可以在此处找到一个完全不同的编程语言 (C#) 的示例,该示例表现出副作用(明显的副作用)。

评论

1赞 cs95 1/17/2018
然后,问题变得过于宽泛。不同的语言可以不同程度地轻松实现这一点。这个问题之所以受到如此多的关注,是因为它是一个特定于 JS 的问答,但这只是我的 2c。
1赞 Edwin 1/17/2018
原因是不同的 C# 和 javascript,所以这个答案是不合法的。
3赞 Dirk Vollmar 1/17/2018
@Edwin:原因完全相同:Unicode 摆弄外观相似的字形或空格字符、竞争条件或比较操作的副作用(后者在我的示例中显示)。
2赞 Dirk Vollmar 1/17/2018
@c ᴏʟᴅsᴘᴇ̴ᴅ:有时从更广阔的角度看问题有助于看到实际问题。
3赞 KCE 1/22/2018
我希望这个答案可以以某种“元”方式标记到这个问题上。看完上面的所有答案后,我感觉 JS 有很多漏洞,但你只是一口气总结了所有的答案。在我看来,你这样做的方式使它成为一个出色的面试问题(如果删除了特定于语言的标签)。太棒了!
26赞 Preda7or 1/17/2018 #20

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

const a = { valueOf: () => this.n = (this.n || 0) % 3 + 1}
    
if(a == 1 && a == 2 && a == 3) {
  console.log('Hello World!');
}

if(a == 1 && a == 2 && a == 3) {
  console.log('Hello World!');
}

我的想法是从数字对象类型方程的工作原理开始的。

25赞 Omar Alshaker 1/17/2018 #21

使用 Symbols 的 ECMAScript 6 答案:

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

由于使用的原因,JavaScript 应该强制转换为接近第二个操作数(在本例中为 、 )的东西。但是在 JavaScript 尝试自行计算强制之前,它会尝试调用 Symbol.toPrimitive。如果提供 JavaScript,则使用函数返回的值。如果没有,JavaScript 将调用 valueOf==a123Symbol.toPrimitive

82赞 Salman A 1/18/2018 #22

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

var  a = 1;
var ᅠ1 = a;
var ᅠ2 = a;
var ᅠ3 = a;
console.log( a ==ᅠ1 && a ==ᅠ2 && a ==ᅠ3 );

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

var a = 1;
var a‌ = 2;
var a‍ = 3;
console.log(a == 1 && a‌ == 2 && a‍ == 3);

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

使用相同的想法可以采用其他技巧,例如,通过使用 Unicode 变体选择器来创建看起来完全相同的变量 ()。a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // true

评论

0赞 Stefan Steiger 3/6/2023
现在这个真是邪恶!谁能想到 1==2 和 2==3 会返回真正的;)
30赞 IceCreamYou 1/20/2018 #23

使用代理

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

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

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

所以:

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

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

评论

3赞 Ry- 1/23/2018
不过,为此使用代理是没有意义的——在对象上以相同的方式定义也同样有效。Symbol.toPrimitive
124赞 Ramin Bateni 1/21/2018 #24

是的,这是可能的!😎

» JavaScript的

if‌=()=>!0;
var a = 9;

if‌(a==1 && a== 2 && a==3)
{
    document.write("<h1>Yes, it is possible!😎</h1>")
}

上面的代码是一个简短的版本(感谢 @Forivin 在注释中的注释),以下代码是原始的:

var a = 9;

if‌(a==1 && a== 2 && a==3)
{
    //console.log("Yes, it is possible!😎")
    document.write("<h1>Yes, it is possible!😎</h1>")
}

//--------------------------------------------

function if‌(){return true;}

如果你只是看到我的代码的顶部并运行它,你会说哇,怎么样?

所以我认为说“是”就足够了,有人说 你:没有什么是不可能的

诀窍:我使用了一个隐藏字符来制作一个函数,其名称类似于 。在 JavaScript 中,我们不能覆盖关键字,所以我被迫使用这种方式。这是假的,但在这种情况下它对你有用!ififif


» C#

我还写了一个 C# 版本(增加了属性值技术):

static int _a;
public static int a => ++_a;

public static void Main()
{
    if(a==1 && a==2 && a==3)
    {
        Console.WriteLine("Yes, it is possible!😎");
    }
}

现场演示

评论

63赞 Clearer 1/22/2018
javascript 版本是真正的危害人类罪,这样做的能力应该是非法的。我认为现在是我们清除世界上所有javacript知识的时候了。
2赞 Forivin 1/24/2018
函数声明可以更短。if‌=()=>!0
7赞 Cerbrus 1/24/2018
你到底为什么要用?无论其余答案如何,这都是不被录用的可靠方法。document.write
4赞 Ramin Bateni 1/24/2018
@Cerbrus,谢谢你的留言。我先写了我的答案,但我把它改成了document.write。我真的总是在我的代码中使用,但在这里我只想在 StackOverflow 代码片段框中向用户显示文本。所以我想展示我的信息比 生成的信息更漂亮。单击我的答案和其他答案上的按钮。SO 代码片段让我使用 html、JS 和 CSS,然后我想在我的答案中使用它并使其变得漂亮。我认为它没有任何负面的副作用,也没有使我的答案变得大或完整。console.logconsole.logconsole.logRun Code Snippet
1赞 Ramin Bateni 1/24/2018
@Clearer,如果联合国公约能够有效地改变世界,那么我们应该有一个比这更美好的世界。我们需要的不仅仅是联合国的声明,在那一天之前,我认为我们可以使用我的这个 Javascript 技巧;)
24赞 gafi 1/22/2018 #25

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

i=0,a={valueOf:()=>++i}

if (a == 1 && a == 2 && a == 3) {
  console.log('Mind === Blown');
}

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

3赞 Jonathan Kuhl 11/5/2018 #26

通过在类声明中重写,可以完成以下操作: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);
}

发生的情况是在每个比较运算符中调用。在第一个上,将等于,在第二个上,将等于,依此类推,因为每次调用时,的值都会递增。valueOfa1a2valueOfa

因此,控制台.log将触发并输出(无论如何在我的终端中),表明条件为真。Thing: { value: 4}

0赞 Nguyễn Văn Phong 4/17/2021 #27

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

ToPrimitive(A)尝试将其对象参数转换为基元 value,通过在 A 上调用不同的 和 方法序列。A.toStringA.valueOf

所以作为其他答案使用,,从整数。我建议使用这样的数组的解决方案。Symbol.toPrimitive.toString.valueOfArray.pop

let a = { array: [3, 2, 1], toString: () => a.array.pop() };

if(a == 1 && a == 2 && a == 3) {
  console.log('Hello World!');
}

这样,我们就可以处理这样的文本

let a = { array: ["World", "Hello"], toString: () => a.array.pop() };

if(a == "Hello" && a == "World") {
  console.log('Hello World!');
}

-8赞 eror programs 9/12/2022 #28

是的,您可以这样做,请参阅以下 JavaScript 代码:

let a = 0 // Create a variable and give it a value
    
if( a !== 1 && a !== 2 && a !== 3 )
  {
    console.log("true")
  }

解决方案说明:

简单地说,我们添加不等号 在 == 符号之前,以便我们告诉语言这些值是 不等于变量中的值

0赞 rjanjic 7/22/2023 #29

如果我们使用 JavaScript 将对象转换为原始值的属性及其 getter 函数,这是可能的。

const a = {
    value: 0,
    valueOf: function() { 
        return this.value += 1; 
    }
}

if (a == 1 && a == 2 && a == 3) {
  console.log('it can')
}