Now, Javascript surely doesn't have the best reputation around for being a well-designed language, but I often feel like being an apologist for it, much in the same way that I truly enjoy the ethos and aesthetics of Bash as a programming language in its own right. They might have warts, but they're not arbitrary. Although Gary Bernhardt's now-classic WAT highlights some ridiculous consequences of Javascript's type conversion system, they are nonetheless explainable in a consistent way. In the JSC interpreter:
> [] + []
> [] + {}
[object Object]
> {} + []
0
> {} + {}
NaN
So while this is certainly WAT, it also can be explained
relatively
easily.
The + operator can either add numbers, concatenate strings,
or be used to specify a positive number. So, [] + [] is really
empty string, and [] + {} is really empty string plus the
string representation of {}, which is '[object Object]'.
In fact, the Node interpreter makes this clear:
> [] + []
''
> [] + {}
'[object Object]'
Then, the final two are interpreted by JSC as empty code blocks followed by something that must be coerced into a numeric value via its string representation. Roughly:
> + Number([].toString())
0
> + Number({}.toString())
NaN
So these at least have some straightforward logical explanations, based on understanding Javascript's parsing and type coercion. But how on earth could we allow this to happen?
> Boolean([0])
true
> [0] == true
false
That the path to a boolean using Boolean is separate from the
path to a boolean using == might seem downright nuts, except
when one realizes that the == operator is used for far more
than truth comparisons. The two use entirely different algorithms
for determining the final evaluation.