DEV Community

Cover image for Why a==1&&a==2&&a==3 is true in JS?
Damian Cipolat
Damian Cipolat

Posted on

Why a==1&&a==2&&a==3 is true in JS?

Maybe you have seen this as a meme or in some JS forum.

I'm sure you have thought, this is impossible to happen, in a code language can this return "true". It's a joke? - Not this returns "true" and there are many reasons for this to happen.

Introduction:

To explain this, is necessary to understand some concepts.

1) Implicit and explicit coercion.

There are two types of coercion explicit and explicit.

Type coercion:

Is the process of converting value from one type to another (such as string to number, object to boolean, and so on). Any type, be it primitive or an object, is a valid subject for type coercion. To recall, primitives are: number, string, boolean, null, undefined + Symbol (added in ES6).

Explicit type coercion:

When a developer expresses the intention to convert between types by writing the appropriate code, like Number(value).

Implicit type coercion:

Values can also be converted between different types automatically, and it is called implicit type coercion. It usually happens when you apply operators to values of different types, like 1 == null, 2/’5', null + new Date(), or it can be triggered by the surrounding context, like with if (value) {…}, where value is coerced to boolean.

There are only three types of conversion in JavaScript:

  • to string
  • to boolean
  • to number

2) Objects, type coercion.

When a JS engine encounters expression like [1] + [4,5], first it needs to convert an object to a primitive value, which is then converted to the final type. And still there are only three types of conversion: numeric, string and boolean.

Numeric and string conversion make use of two methods of the input object: valueOf and toString . Both methods are declared on Object.prototype and thus available for any derived types, such as Date, Array, etc.

In general the algorithm is as follows:

  • If input is already a primitive, do nothing and return it.
  • Call input.toString(), if the result is primitive, return it.
  • Call input.valueOf(), if the result is primitive, return it.
  • If neither input.toString() nor input.valueOf() yields primitive, throw TypeError.

3) Functions toString and valueOf

Take a look of two object prototype methods.

object.toString()

The method .toString() is used when an object is coerced into a string. This is helpful when you want to get a nice string representation of an object vs. the not-so-useful "[object Object]".

const s = {
  name: 'Damian',
  surname: 'Cipolat',
  toString: function() {
    console.log('LOG', this.name,this.surname);
    return `Fullname: ${this.name},${this.surname}`;
  }
}
console.log(s);
// { x: 7, y: 3, toString: [Function: toString] }
console.log(s + '');
// 'Square: 7,3'
console.log(+s);
// NaN
Enter fullscreen mode Exit fullscreen mode

object.valueOf()

The method .valueOf() is used when an object is coerced into a primitive value such as a number. If you’ve ever added a number to an object and ended up with a value of NaN, then this method is your friend.

const box = {
  l: 7,
  w: 3,
  h: 4,
  valueOf: function() {
    return this.l * this.w * this.h
  }
}
console.log(box)
// { [Number: 84] l: 7, w: 3, h: 4, valueOf: [Function: valueOf] }
console.log(String(box))
// [object Object]
console.log(+box)
// 84
Enter fullscreen mode Exit fullscreen mode

Explanation:

Ok, it's time to discover the magic, why a==1&&a==2&&a==3 is "true"? To make this expression success, we can override the function toString, this function is used in the implicit type coercion of the operator "==".

This is the full code:

const a = {
  tmp: 1,
  toString: function () {
    console.log('TO STRING');
    return a.tmp++;
  }
}

if(a == 1 && a == 2 && a == 3) {
  console.log('JS Magic!');
}
Enter fullscreen mode Exit fullscreen mode

So the reason here is the toString function is called 3 times and the TO STRING appears in the console output.

Readings

Some interesting links to continue reading.

Top comments (0)