Categories
ecmascript-6 javascript

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

2621

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 true in JavaScript?

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.

17

  • 11

    Comments are not for extended discussion; this conversation has been moved to chat.

    – deceze

    Jan 16, 2018 at 8:20

  • 119

    To the people that apparently voted to cloae this as too broad: is that a dig at Javascript, saying that there are too many valid answers?

    Jan 16, 2018 at 23:15

  • 29

    Some people sit around philosophizing about what’s possible. Others focus their efforts on whether or not they are building viable, business correct products for their clients. IMO, this question has no practical utility beyond the fact that you should never ask these kinds of questions in an interview or write this kind of code. That’s why it should be closed. I mean really, does the business realize they paid somebody real money to sit around and talk about this stuff?

    Jan 17, 2018 at 16:10


  • 18

    After reading the answers, the morals of the story are: don’t use == when you mean ===, have a coding standard that bans non-ASCII variable names, and have a linting process which enforces the previous two morals.

    Jan 17, 2018 at 18:00

  • 91

    Moderator note: Stack Overflow has had a history of people chiming in with answers in different languages to the one in question. These are attempts to answer the question because they are solutions to the general problem, albeit in a different language. Please refrain from flagging them as “not an answer”. Having said that, please also refrain from posting more answers in different languages – there is a reason this question is specific to JavaScript, as pointed out by comments under some of these other answers, and there is a reason we like our language-specific questions to remain so.

    – BoltClock

    Jan 18, 2018 at 5:31


3448

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.

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 valueOf if it is callable, and failing that, it will call toString. I used toString in this case simply because it’s what came to mind, valueOf would 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.

19

  • 74

    Could you achieve this by altering the implied valueOf() operation?

    Jan 15, 2018 at 20:37

  • 47

    Yes, valueOf works in place of toString for the same reason

    – Kevin B

    Jan 15, 2018 at 20:38

  • 4

    Comments are not for extended discussion; this conversation has been moved to chat.

    – deceze

    Jan 16, 2018 at 8:24

  • 15

    According to this a number conversion will be tried first so valueOf is slightly better.

    – Salman A

    Jan 16, 2018 at 12:31


  • 7

    @Pureferret the left-hand side of the equality comparison is an object, not a number. That that object has a number property on i doesn’t bother the engine. 😉

    Jan 16, 2018 at 13:07

2125

+200

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 if statement (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:

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.

Don’t do this. Seriously.

Edit: It has come to my attention that (although not allowed to start a variable) the Zero-width joiner and Zero-width non-joiner characters are also permitted in variable names – see Obfuscating JavaScript with zero-width characters – pros and cons?.

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

13

  • 386

    Judging by the odd spacing in the original question, I think this is EXACTLY the answer the interview question was looking for – exploiting non-space characters that look like spaces. Good spot!

    – Baracus

    Jan 16, 2018 at 7:09


  • 20

    @Baracus It was RonJohn who noticed the weird spacing in his comment on Kevin’s answer which reminded me of this (awful) technique, so I can’t take credit for spotting it. I was kinda surprised noone had already answered with this though, as it went around my work a few years ago because of a blog post somewhere – I kinda assumed it was pretty common knowledge by now.

    – Jeff

    Jan 16, 2018 at 7:12

  • 107

    Of course, this is banned as a standard loophole, which also applies to interviews. [citation needed]

    – Sanchises

    Jan 16, 2018 at 12:23

  • 14

    Considering the original spacing, it might be even worse, i.e. a variable var ᅠ2 = 3 has been used; so there are the three variables aᅠᅠ= 1, ᅠ2 = 3, a = 3 (a␣ = 1, ␣2 = 3, a = 3, so that (a␣==1 && a==␣2 && a==3))…

    – Holger

    Jan 17, 2018 at 7:15


  • 3

    @AL-zami there is an extra character in two of the variables, which shows on your screen as a space, but is interpreted as part of the identifier, meaning there are three separate variables – a, a and a – the extra character is the Hangul half-width space.

    – Jeff

    Jan 17, 2018 at 18:27

642

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 with statement to let a evaluate to three different values.

… 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.");
  }

11

  • 67

    Yes I was trying the same thing 🙂 So the correct answer in the interview would be, “It cannot happen in my code because I never use with.”

    – Pointy

    Jan 15, 2018 at 20:42

  • 8

    @Pointy – And, I program in strict mode where with is not allowed.

    – jfriend00

    Jan 15, 2018 at 20:44

  • 7

    @Pointy in the accepted answer they do something similar without the with so it can happen

    – J_rite

    Jan 16, 2018 at 11:17

  • 2

    @jorrit no one would use ==. And === prevents the accepted answer

    Jan 16, 2018 at 12:48

  • 4

    @JonasW. A lot of people still use == but I haven’t seen with since … well actually never outside of JS documentation where it says “please don’t use that”. Anyway, a nice solution.

    – wortwart

    Jan 16, 2018 at 19:31