If you think JavaScript is an odd language, just wait: a few experiments with the addition operator will really leave you scratching your head
Every now and then, I am reminded that as corny as the term “web surfing” may sound, it is sometimes an amazing experience. Recently, while digressing from a sub-reference of a side-topic that was tangentially related to a random blog post I stumbled across while procrastinating, I found a video titled: “WAT”. If you have even the slightest appreciation for, or hatred of JavaScript, it is a hilarious four minutes.
SPOILER ALERT: Try to watch the video before going any further. It’s much more enjoyable if you don’t know what is coming.
https://www.destroyallsoftware.com/talks/wat
Now that you have (hopefully) watched the video:
I have no idea who Gary Bernhardt is, but he makes some interesting points. Here are a few highlights:
QUESTION: What is the return value of this expression? [] + [];
ANSWER: An empty string
QUESTION: What is the return value of this expression? [] + {};
ANSWER: “[object Object]”
QUESTION: What is the return value of this expression? {} + [];
ANSWER: 0
There are a few more examples, but the overall message is: the JavaScript addition operator produces very odd results in corner cases. I must admit, I’ve never thought to explore this behavior and not only were my answers to all three of the above questions wrong, but I was pretty shocked by the correct answers.
Inspired, I decided to try a few of my own.
Array + Object
While [] + {} does return “[object Object]”, that return value is not an object, but simply a string whose value is: “[object Object]”. To prove this, I did the following:
1 2 3 4 5 6 7 |
var foo = [] + {}; foo.color = "red"; foo.speed = 150; typeof foo; // string console.dir(foo); // same thing as console.dir("[object Object]") |
Array + Function
1 2 3 4 |
function foo(){return true}; foo + []; // "function foo(){return true}" [] + foo; // "function foo(){return true}" |
The return value of this is the exact same thing as foo.toString();
Object + Function
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function foo(){return true}; foo() + {}; // "true[object Object]" foo + {}; // "function foo(){return true}[object Object]" {} + foo; // NaN {} + foo(); // 1 !{} + foo(); // 1 !!{} + foo(); // 2 !!!{} + foo(); // 1 typeof {} + foo(); // "objecttrue" typeof !{} + foo(); // "booleantrue" typeof !!{} + foo(); // "booleantrue" typeof !{} + !foo(); // "booleanfalse" typeof !!{} + !foo(); // "booleanfalse" |
As I tried yet another combination, I started to notice a pattern. When using the typeof operator, the return value was a concatenation of the “toString” methods for each value that was being added. So, if the expression is: {} + foo(), the result is “object” and “true” combined, which is: “objecttrue“. ok, got it.
But the fact that foo + {} returns NaN, makes no sense to me. And then there are a few more adventurous roads one might waddle down:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[] - []; // NaN {} - {}; // NaN [] - {}; // NaN {} - []; // -0 {} + [] + {}; // "0[object Object]" {} + [] + []; // "0" function foo(){return true}; {} - foo(); // -1 {} - foo; // NaN typeof {} - foo; // NaN typeof {} - foo(); // NaN |
OK Kevin, so what’s your point?
That’s a fair question. Ultimately, since we never do those kinds of things in our JavaScript code (right? right? : – ), none of this should matter. But as I played around with these examples, two important things came to mind:
Troubleshooting
If you ever replicate these kinds of patterns by accident, it results in the kind of hair-pulling frustration that makes you start to actually believe that there is a dark lord of JavaScript controlling your browser. When trying to track down what seems like unexplainable behavior in your code that is clearly a bug, in addition to that missing semi-colon, implied global, or accidental use of “=” instead of “===”, consider these kinds of patterns. While they all seem very unlikely, typos can happen, and are sometimes hard to spot.
A Deeper Understanding
JavaScript is a truly odd specification. While there are plenty of odd things about it that we do know, there are always a few strange patterns like these that one might not have come across yet. There may or may not be anything useful about all of this, but as JavaScript’s ubiquity and maturity continue, any deep understanding of its quirks and idiosyncrasies can only benefit the developer.
VIDEO LINKS
Jump to: 1:22 for the good parts
(If this video link ever stops working, just google: “A lightning talk by Gary Bernhardt from CodeMash 2012”. There are many pages out there that feature this video)
https://www.youtube.com/watch?v=Othc45WPBhA
https://www.destroyallsoftware.com/talks/wat