Recently a talk given by Gary Bernhardt at CodeMash has been doing the rounds. In it, he pokes fun at some apparently crazy behaviours in Ruby and Javascript.

While I might not be able to persuade you that all of the things he com plains about make sense, I hope I’ll be able to show you some of the reasons that javascript behaves as it does.

The + symbol

The + symbol in javascript can mean one of three things.

It can be an infix addition operator where it operates on two numbers.

It can be an infix string concatenation operator where it operates on two strings.

It can be a prefix ‘this number is positive’ operator where it operates on a single number.

What makes all of this slightly more complicated is that javascript has automatic type coercion, so if you use something that isn’t a number or a string before or after your + symbol, then javascript is going to automatically convert whatever you did use to be either a string or a number.

boolean, null, undefined coerce to a number (true = 1, false = 0, null = 0, undefined = NaN)

object, array, function all coerce to a string.

So when you see

[] + []

You know that javascript is going to coerce both of those empty arrays to a string and do a string concatenation on them.

When an array is coerced to a string, you get a comma separated list of its contents, so the result will be an empty string.

[] + {}

In this case, the empty object on the right hand side is again going to be coerced to a string. Since it doesn’t implement a toString method, it’ll pick up the toString method of the default Object by inheritance which returns the string [object Object] for objects, so we’re concatenating the empty string with the string "[object Object]" .

Empty Code Blocks

Now we come to a parsing weirdness in javascript. You might have spotted that we use curly braces for two distinct things in javascript. One of them is to indicate code blocks (like after an if statement or as part of a function definition), and the other is to write object literals (JSON as it’s often called). In some languages code blocks can appear in most places within the code and indicate a new scope. Javascript doesn’t use block scoping (yet), but it still allows code blocks to appear inside normal code. Which means that sometimes when you write {} the javascript parser understands that as an empty code block and sometimes when you write {} it understands that as an empty object literal. Generally speaking, if the { appears at the beginning of a statement it’s going to be interpreted as a code block. You can force the object literal understanding by wrapping the literal in normal brackets.

{} + []

In this case the empty curly braces are interpreted as an empty code block, which means that the + appears at the beginning of the next statement, meaning that here the + is a prefix operator that indicates a number is positive. The + prefix operator can only accept a single number argument, so it will always coerce its argument to a number.

In an extra wrinkle, the way javascript coerces an object, a function or an array to a number is via first coercing it to a string. An empty string coerces to 0. So for example:

+ [] === 0 // because the empty array becomes an empty string which becomes 0 + [1] === 1 // because the array with 1 in it becomes a string with 1 in it which becomes 1 isNaN(+[1, 2] ) // because the array with 1, 2 in it becomes a string "1,2" which is not a number. +({toString: function() {return "3"}}) === 3

So an empty object coerces to a string [object Object] which then coerces to NaN when it has to become a number for the prefix + operator in the following statement:

{} + {}

The – Symbol

Unlike +, the symbol – is comparatively simple. It has only two meanings, an infix meaning which requires two numbers and a prefix meaning which requires one number. You already know that strings that don’t represent numbers get coerced to NaN when they are required to turn into numbers, so it should be no surprise that

isNaN("wat" - 1)

Why does this matter?