The Curious Case of The Javascript Trinity

Javascript is a very interesting language. It is used virtually everywhere and it has the biggest online community among all the other programming languages, seeing these facts an outsider who doesn’t know anything about javascript may assume that it’s the most perfectly written programming language ever.

But alas nothing is perfect and javascript is not an exception. If you ask any javascript developer to name one thing that can be done better in vanilla javascript and 9 out of 10 would say implicit type coercion.

What is Implicit Type Coercion?

Converting a value of one type to another is called type coercion. Javascript has a set of rules for converting type implicitly. This implicit conversion often behaves in ways that can make anyone scratch their heads. Initially, this behavior was added to make javascript beginner-friendly but as its turns out it causes more hassle than it’s worth.

In smaller programs, these anomalies can be easily caught and rectified, but when the code base grows it becomes almost impossible to catch these.

Let us see one of these anomalies with some more detail.

The Javascript trinity

credits : https://javascriptwtf.com/

If you have been on any online javascript forum, you would have seen this image. Implicit type conversion rears its ugly head here.

Now lets break this down

  • 0 is a number.
  • “0” is a string with a 0.
  • [] is an empty array.
  • “\t” is a string with a tabspace.

Case 1:

console.log(“0”==0) //->true

When a string and a number get compared javascript type converts the string to a number, this is done by the ToNumber abstract operation. So here we can represent this like

console.log(Number(“0”)==0) //->true

and we know that 0==0 so hence we get true.

Case 2:

console.log("\t"==0) //->true

Now, this one seems a bit weird but it follows the same rules as the one above.

Confused?

Let me break it down for you. Like I said in the previous case in a string to number comparison the string always gets type converted into a number by the ToNumber abstract operation. Hence we can represent the comparison like this,

console.log(Number("\t")==0) //->true

What the Number() does is it internally uses the ToNumber abstract operation on the character gets passed to it and guess what the numerical value of white space is 0.

Now we have 0==0 which is true.

Case 3:

console.log([]==0) //->true

Now we come to the weirdest case in our Javascript trinity. Array is not a primitive datatype yet an []== 0 returns true.

Confused?

To be honest, this one got me the first time too, But trust me this behavior is completely standard.

We saw in the previous cases that when doing a string-to-number comparison the ToNumber operation gives us the numerical value which we use for the comparison, this case is no different.

The thing is ToNumber will use two more internal operations, ToPrimitive and [[DefaultValue]].

ToPrimitive will take 2 arguments in our case the array and the hint type(the type we need it converted to) which is Number.

Now the ToPrimitive calls the [[DefaultValue]] operation also with the hint type Number. The [[DefaultValue]] operation tries to convert the given value into a primitive type. In our case, the array we pass gets converted into a string.

console.log([].toString()) //->""

Now lets do the string to number conversion.

console.log(Number("")) //->0

And finally the moment we have been waiting for! The empty array has been type converted into a number!

And our expression ends up looking like this 0==0 which is true!

Now about the other cases

All the three cases that we saw above were a case of Number to String and Number to Object(arrays are defined as objects in javascript) comparisons, in both the scenarios the String and the Object gets converted into a Number.

In the three falsy cases we have String to String comparison and String to Object comparison. Let’s look at these cases.

String to String Comparison

console.log("0"=="\t") //->false

Both the values are of type string which is a primitive type and hence no type coersion takes place. So obviously “0” will not be equal to “\t”.

String to Object Comparison

console.log("0"==[]) //->false
console.log("\t"==[]) //->false

In these comparisons, the primitive type is String so javascript converts the empty array into a string. We know that the empty array([]) converts to an empty string(“”). Hence “0” will not be equal to “” and “\t” will not be equal to “”.

The above examples can be expressed as follows

console.log("0"==[].toString()) //->false
console.log("\t"==[].toString()) //->false

Intresting isn’t it?

When you see the javascript trinity at face value it just seems like a funny meme poking fun at javascript(let’s be honest it is a bit funny). But when you analyze the principles behind the meme you are just left in awe.

If you are curious about the rules followed in these conversions

Check out: https://262.ecma-international.org/5.1/#sec-11.9.3

Conclusion

On a closing note, I’d like to mention something that I should have mentioned at the start of this blog.

Don’t use == for comparision😂

Use === which compares the type and the value.

And also there is this awesome thing called Typescript, Which overcomes all of this implicit type coercion nonsense by using strong typing.

So in conclusion switch to typescript!

I'm a Techie, Travaler and a photographer!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store