Blog

Javascript WAT: ECMAScript Abstract Equality Comparison Algorithm

Written by Metal Toad Staff | Oct 29, 2014 12:00:00 AM
Filed under:

I'm assuming most of you saw Gary Bernhardt's talk from CodeMash 2012 on some WAT™ features in Ruby and JavaScript. If not, I highly recommend you do as it's thouroughly amusing. No, seriously. Go ahead, I'll wait...

Before I say anything else, I am going to go on the record and say that I love JavaScript. It is one of my favorite programming languages. I find it therapeutic most of the time. It is a prototypal, dynamic and "weakly typed" programming language that treats functions as first class citizens. Transitioning from a class based OOP to a prototypal OOP can be a struggle at first, but as soon as you accept the simple truth that there is no spoon, you will realize that you know kung-fu.

That being said, every once in a while you will run into a JavaScript "feature" that will have you scratching your head and going:

I recently watched JSConf video by Shirmung Bielefeld on equality operators in JavaScript and I found the following conundrum in the comment section:

1. if([]) { console.log('True'); } else { console.log('False'); } // returns True :D
2. [] == false // empty list compared to false, returns true
3. [] == true // empty list compared to true, returns false

Now, the if statement makes sense. I know that all objects in JavaScript are truthy (even empty objects) and JS arrays are objects, so the if statement evaluates to true as expected. However, [] == false evaluating to true is a prime example of JS WAT™ moment. I would expect both 2. and 3. to evaluate to false, or at worst [] to resolve to its truthy value and 3. to evaluate to true and 2. to evaluate to false. However, that would make sense and would make JS gremlins unhappy and ain't nobody got time for that.

On a serious note, the answer to this lies in ECMAScript's spec for Abstract Equality Comparison Algorithm - better known as: == operator. Let's go step by step and take a look at how the JavaScript engine interprets [] == false.

7. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
// [] == false becomes [] == 0
 
9. If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.
// Now [] is being converted to primitive by calling implementation of [[DefaultValue]] with hint of string, which is effectively calling toString on an empty array (which returns empty string or "").
// [] == 0 becomes "" == 0
 
5. If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
// "" == 0 becomes 0 == 0, which evaluates to true.

So it is not a gremlin, it's a "feature" after all. Now we know ECMAScript spec for == operator and we can develop some intuition to how objects will be evaluated via Abstract Equality Comparison Algorithm. Using the same logic as above, we know that {} == false will also be evaluated to true, right? Wrong! The difference is subtle and consistency is overrated. I'll leave this one for you to figure out. If you get stuck and if you are interested as to why this is, leave a comment below and I'll follow up. Or even better, share your favorite WAT™ JavaScript moment.