Can a == true && a == false be true in JavaScript?

  sonic0002        2018-03-25 03:39:43       19,673        2    

JavaScript is a weak typed language and it has a loose comparison feature where two objects/values of different type can be compared using == operator. This provides developers great flexibility and confusion at the same time. 

Before understanding how == works in JavaScript, can you first answer the question in the post title? Can a == true && a == false be true in JavaScript? Normally, we would think that this expression will always return false since a can be either true or false but cannot be both. However, in JavaScript, the above expression can return true indeed.

If we have below code, we will get the above expression to return true:

const a = {
    num: 1,
    valueOf: function(){
        return this.num--;
    }
};
console.log(a == true && a== false);

To understand why above code returns true, the explanation of how == works in JavaScript is needed. According to ECMAScript Spec, below describes the steps for performing == comparison.

  1. If Type(x) is the same as Type(y), then
    1. Return the result of performing Strict Equality Comparison x === y.
  2. If x is null and y is undefined, return true.
  3. If x is undefined and y is null, return true.
  4. If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).
  5. If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
  6. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
  7. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
  8. If Type(x) is either String, Number, or Symbol and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).
  9. If Type(x) is Object and Type(y) is either String, Number, or Symbol, return the result of the comparison ToPrimitive(x) == y.
  10. Return false.

In above code block, x is a which is an object while y is a boolean value which has type Boolean.  Hence when doing comparison a == true, it will have below execution sequence:

  • Evaluate step 7, this step will first convert true to 1
  • Next, it will evaluate step 9, it converts a to a primitive value.
  • According to rules of ToPrimitive, a will be converted to a number finally and it will call object a's valueOf() method.
  • Since a has valueOf() defined and it will return 1 when called the first time
  • After all above steps, a == true will return true since 1 == 1

ToPrimitive:

  1. Assert: input is an ECMAScript language value.
  2. If Type(input) is Object, then
    1. If PreferredType was not passed, let hint be "default".
    2. Else if PreferredType is hint String, let hint be "string".
    3. Else PreferredType is hint Number, let hint be "number".
    4. Let exoticToPrim be ? GetMethod(input, @@toPrimitive).
    5. If exoticToPrim is not undefined, then
      1. Let result be ? Call(exoticToPrim, input, « hint »).
      2. If Type(result) is not Object, return result.
      3. Throw a TypeError exception.
    6. If hint is "default", set hint to "number".
    7. Return ?OrdinaryToPrimitive(input, hint).
  3. Return input.

And OrdinaryToPrimitive

  1. Assert: Type(O) is Object.
  2. Assert: Type(hint) is String and its value is either "string" or "number".
  3. If hint is "string", then
    1. Let methodNames be « "toString", "valueOf" ».
  4. Else,
    1. Let methodNames be « "valueOf", "toString" ».
  5. For each name in methodNames in List order, do
    1. Let method be ? Get(O, name).
    2. If IsCallable(method) is true, then
      1. Let result be ? Call(method, O).
      2. If Type(result) is not Object, return result.
  6. Throw a TypeError exception.

Next the expression a == false will be evaluated, the steps are similar to what a == true does. However, this time when a.valueOf() is called, the value it returned will be 0. And false will also be converted to 0, a == false will return true now.

The final result will be true with above code block. By knowing how == comparison works, many other expressions seem impossible at first glance can actually be possible. 

For example, there is also another famous interview question about JavaScript saying can a == 1 && a == 2 && a == 3 be true?

The answer is Yes. Just need to define an object as below:

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

Apparently in reality we would rarely see this kind of code in our application. The purpose here is to let you know that don't be surprised if you see some weird behavior in JavaScript. And also a rule of thumb is to stick to use === whenever you can because it does the strict comparison which requires two objects have the same type.

==  JAVASCRIPT  INTERVIEW QUESTION  COMPARISON 

       

  RELATED


  2 COMMENTS


Sören [Reply]@ 2018-04-03 02:44:45

Hi :)

I was wondering if there are symbols or functions I can use to make 

const a = {_num: 1}

console.log(a === 1 && a === 2 && a === 3); // Wanted output: true

As far as I could find neither valueOf nor any other symbol or function is called. I could only find a way with a scoped variable:

(() => {let _ = 1;Object.defineProperty(window, 'a', {get(){return _++}})})();

 

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

Is there another way?

Anonymous [Reply]@ 2018-04-05 12:02:49

Brilliant!!!



  RANDOM FUN

How to recover from this?