At CodeMash 2012, Gary Bernhardt gave
a now infamous lightning talk that has become known simply as The WAT
Talk, in which he presents
several of the more surprising behaviors of Ruby and JavaScript. I’ve
passed the video around quite a few times, and I’ve pointed out some other
JavaScript behaviors that seem pretty outlandish at first sight. But I’m
feeling a little guilty about poking fun at JavaScript, so I wanted to
dive further into these WATs and talk about *why* they happen.

I’m not here to defend JavaScript—it doesn’t need my defense. It’s not a perfect language, and it’s not my favorite language, but it is the single most popular language on the web right now, and because more and more people are using it for the first time, I think it’s worth the effort to go over some of these unexpected behaviors to help newcomers avoid common pitfalls.

But first, the WATs.

# The WATs

```
> [] == []
false
> [] == ![]
true
> [] + []
''
> [] - []
0
> [ null, undefined, [] ] == ',,'
true
> [] + {}
'[object Object]'
> {} + []
0
> Math.min() < Math.max()
false
> 10.8 / 100
0.10800000000000001
```

**WAT?!**

# Background: Type Coercion

I’m putting the cart before the horse a bit here, but I’m going to go
ahead and spoil bits of the rest of this post by telling you up-front that
many of these WATs involve *type coercion*. JavaScript is a dynamically
typed language, but it is also a weakly typed language, meaning that
variables may be automatically changed from one type to another in fairly
wide contexts. Coercion is distinct from casting, in which a variable is
changed to another type, but only if you’re changing the interpretation of
its contained data or if the new type is higher up in the same type
hierarchy. For example, in Java when you cast a long to an int, you’re
asking that the top 32 bits be ignored and the remaining bits be treated
as a 32-bit signed integer; when you cast a String to an Object, you’re
asking the compiler to treat calls to the reference as if they were calls
to an instance of Object.

Type coercion, on the other hand, is happy to turn an int into a String for you. In a language like Java, it happens only in a very few places, and is usually pretty obvious and easy to predict. If you’re used to these rules, though, JavaScript’s coercion can be pretty surprising. Not only will it turn a Numeric type into a String for you, but it will go the other direction too.

And now, without further ado, on to the list of WATs.

# WAT Number One: Empty Array Not Equal To Empty Array

```
[] == [] => false
```

There’s actually a lot going on here. At first glance, it looks absurd:
*an empty array does not equal itself?!* But that’s not really the
question we asked.

So, what question *did* we ask? Like a Facebook relationship status, it’s
complicated. JavaScript’s double-equals equality operator has a fairly
extensive set of rules that make it more difficult to use than the
double-equals operator in other C-like languages.

What we’re really asking here is, “Is one instance of an empty array equal
to another instance of an empty array?” In JavaScript, the answer is no,
because when you’re comparing two instances *of the same type*,
double-equals will return true if and only if they are the same
instance. We’ve created two instances here, one on the left side of the
operator, and one on the right side of the operator. They are not the same
instance, so `[] == []`

evaluates to false.

# WAT Number Two: Empty Array Equals Bang Empty Array

```
[] == ![] => true
```

OK, now what is *this* nonsense?

Although I agree it’s pretty confusing, it’s not nonsense *if* you know
the rules and *if* you apply them in the right order. Here, the bang
operator binds more tightly than the double equals, so the first thing we
have to do is evaluate ![]. It so happens that in JavaScript, the bang
operator coerces whatever it’s applied to into a boolean value. An empty
array, in JavaScript, is considered “truthy”, so when it’s coerced into a
boolean, it becomes true, not false, and the bang operator converts the
true into a false. Now the question looks more like this:

```
[] == false => true
```

OK, but that *still* looks bizarre, right? We just said that an empty
array was truthy, not falsy, and true certainly does not equal false!

But, like I said, double-equals is complicated. The rules say that when
you’re comparing an Object on the left and a boolean on the right, you
convert both sides to *numbers* (the same as applying the Number()
function), and re-run the comparison.

In JavaScript, `Number([]) => 0`

, and `Number(false) => 0`

, so now we
have a new question:

```
0 == 0 => true
```

That’s more like it. Yes, zero is equal to zero.

# WAT Number Three: Empty Array plus Empty Array Yields Empty String

```
[] + [] => ''
```

This is actually fairly straight-forward once you understand that the addition operator in JavaScript only operates on two types: Strings and Numbers. We’re asking JavaScript to add two Arrays, which it doesn’t know how to do, so it coerces them both into Strings and then concatenates them together. Calling [].toString() yields an empty string, and concatenating two empty strings together yields an empty string.

# WAT Number Four: Empty Array minus Empty Array Yields Zero

```
[] - [] => 0
```

This case is *very* similar to the previous case, except we’re using the
minus operator instead of plus. Again, JavaScript doesn’t know how to
subtract arrays, and while Strings can be concatenated with the plus
operator, Strings don’t understand the minus operator at all, so
JavaScript coerces both sides into Numbers for us, instead of Strings. If
you call `Number([])`

in JavaScript, you get 0, so what we’re really
saying is:

```
0 - 0 => 0
```

That makes a lot more sense.

# WAT Number Five: An Array Of Values Is Equal To A Weird Looking String

```
[ null, undefined, [] ] == ',,' => true
```

Woah, hey now. What’s this all about? It’s all about coercion and that double-equals operator again.

Here, we are using double-equals to compare an Object and a String. The
rules say that when you’re comparing an Object on the left side and a
String on the right side, you have to perform some operations to the left
hand side to figure out how to do the comparison. The end result of this
is that the array on the left is coerced into a String (by calling its
toString() function, if it has one). And it just so happens that calling
[null, undefined, []].toString() yields the String “,,” /(Why? Because
null, undefined, and [] all turn into empty strings, and JavaScript joins
those empty strings with commas)/. So we’re *really* asking if two strings
are equal:

```
',,' == ',,' => true
```

Yes, they are, so it evaluates to true.

# WAT Number Six: Array Plus Object Yields The String “[object Object]”

```
[] + {} => '[object Object]'
```

This is still more type coercion. We’ve already discussed how the addition operator only operates on Numbers and Strings, and what’s happening here is JavaScript converting both sides of the operator into Strings. An empty array, as we’ve already seen, gets converted into an empty string. But what about {}?

In JavaScript, `{}`

is (usually!) an Object literal. It’s really saying,
“Make an instance of Object for me, please.” So now we’re concatenating an
empty string, and the result of coercing an Object instance into a String.

Well, the default `toString()`

for Object returns the string “[object
Object]”. The code now becomes:

```
'' + '[object Object]' => '[object Object]'
```

# WAT Number Seven: Object Plus Array Yields Zero

```
{} + [] => 0
```

BUH!

Wait wait wait. We *just* got finished explaining how JavaScript coerces
both sides into a String, right? So shouldn’t this be exactly the same as
the previous example?

Well, not quite.

We’ve actually been bitten by a bizarre edge case here. JavaScript has
misunderstood our intentions completely. As it scanned the line, it
interpreted the initial {} not as an object literal, but rather as an
*empty code block*. Yes, really. In essence, it has just decided to ignore
it completely, and treat the line as if it were written this way:

```
+ [] => 0
```

That in itself would seem nonsensical, except that JavaScript also allows unary addition operator. Unary addition + x is equivalent to calling Number(x), so what you end up with is an empty Array instance being converted to a number, which yields 0.

# WAT Number Eight: Math.min() is greater than Math.max()

```
Math.min() < Math.max() => false
```

Before we explore this, let’s look at how these functions are defined, and what they return.

`Math.min()`

and `Math.max()`

are being used *deceptively* in this
WAT. Most languages define global min and max values, and JavaScript does
too—but not with `Math.min()`

and `Math.max()`

. Instead, JavaScript
gives us `Number.MIN_VALUE`

and `Number.MAX_VALUE`

, and these behave
exactly as you would expect:

```
> Number.MIN_VALUE < Number.MAX_VALUE
true
> Number.MIN_VALUE > Number.MAX_VALUE
false
```

Math.min() and Math.max(), on the other hand, are functions used to find the min and max values of a sequence of numbers. If you use them correctly, they make sense:

```
> Math.min(27, 9, 13)
9
> Math.max(27, 9, 13)
27
```

And if you call them without arguments?

```
> Math.min()
Infinity
> Math.max()
-Infinity
```

Why? It’s how they’re implemented. Math.min() initializes its return value to Infinity and then looks for the smallest number in the sequence. There isn’t one, so it returns Infinity. Similarly, Math.max() initializes its return value to -Infinity, and looks for the largest value. There isn’t one, so it returns -Infinity.

The final form of this makes a lot more sense:

```
Infinity < -Infinity => false
```

# WAT Number Nine: Floating Point Madness

```
10.8 / 100 => 0.10800000000000001
```

This is probably the sanest WTF on the page. If you’ve ever worked with floating point numbers in any language, this kind of thing is probably already familiar to you. It’s just a run of the mill floating point accuracy issue.

But 100 is an integer, isn’t it? Well, no. Not in JavaScript. JavaScript
numbers come in only one flavor: IEEE-754 floating point. There *are no
integers in JavaScript*. This may in fact be the single most important
thing to know about JavaScript, especially if you’re doing any kind of
math.

This problem would present itself in C, too. Example:

```
#include "stdio.h"
int main(void) {
float f = 10.8f / 100.0f;
printf("%.16f\r\n", f);
}
```

If you run this code, what do you get? Not 0.108! On my computer, you get 0.1080000028014183, because of inherent limitations in floating point accuracy.

JavaScript isn’t alone here, it’s just more likely to bite you because you
*have* to use floating point, while you’re free to use other numeric types
in other languages.

# Conclusion

I’ll be frank: JavaScript is *weird*, but it’s here to stay, and if you
find yourself working in it, it’s good to immerse yourself in the
weirdness and try to get a feel for what’s going on under the hood. I hope
this post has helped to clear up a handful of the stranger seeming cases,
especially if you’re new to it and coming from the background of another
language.

## Comments