Kevin Chisholm – Blog

Web Development Articles and Tutorials

JavaScript: WAT!

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? {} + [];

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:

Array + Function

The return value of this is the exact same thing as foo.toString();

Object + Function

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:

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

The WHY behind the WAT- An explanation of JavaScript’s type system

January 18, 2018

Note: This article was originally posted on Medium.com via Daily JS. However, I’m reposting on my blog to preseve the text. Unfortunately, images did not transfer over so well…

javascript wat presentation

So if you’ve been in the JavaScript world for a bit, you’ve probably come across Gary Bernhardt’s “Wat” talk.

For those of you who haven’t seen it, you are seriously missing out and I would highly suggest that you go and check the talk out .

A brief summary of the video:

Bernhardt (the person giving a presentation at CodeMash 2012) discusses some of the unexpected behavior in Ruby and JavaScript. Around two minutes into the presentation, he starts ripping into JavaScript specifically with his hilarious use of sarcasm to get one point across:

JavaScript is…weird (to say the least).

To illustrate this point, he brings up a few examples of illogical operations that produce unexpected results.

Now imagine that you are an undergraduate and you’re the instructor for an Intro to JavaScript class. You thought it’d be comical to show Bernhardt’s video in the first lecture to show how quirky and funny JavaScript is, and then you go onto to talk about basic JS syntax, types, functions, closures, etc. But before you do that, someone asks you

“Why is array plus array equal to empty string?”

That’s when it hits you that you have no idea what is going on in that video or JavaScript’s type system in general…at least that’s where I found myself about a week ago.

So, in order to prevent developers from giving semi-coherent, hand-wavy explanations of why JS works in the way it does (and of course to educate you, the reader), let’s dive into the Why behind the WAT.

I can do types good, right?

javascript wat presentation

So let’s begin at the basics. There are 5 different literal (things you can declare instantaneously) types that exist in JS:

Numbers (e.g. 1 , 2 , 1.28 , NaN , Infinity , etc.)…note that NaN (not a number) is a number. From the ECMA spec:

4.3.20 Number type: set of all possible Number values including the special “Not-a-Number” (NaN) values, positive infinity, and negative infinity

Strings (e.g. 'xyz' , "abc" ) Pretty straightforward

Boolean (just true and false )…there’s a whole article that can be written about truthy vs falsy values. But for the moment, we’re going to skip that.

Objects (e.g. {name:'abhi', dob: '1997'} )

Array (e.g. [1,2,'hi'] )

Of these literals, only booleans, numbers, and strings are primitives. There are also a couple of other primitive values ( undefined and null ).

**Let’s do an exercise: **Given that the typeof function will output a string representing the type of a variable passed to it, what is typeof([1,2,3]) ?

Well…it’s actually 'object' .

In JavaScript, objects and arrays are handled nearly identically because arrays are just instantiations of objects. The difference is the following:

  • While objects are just an unordered map from string keys to values, arrays are an ordered list of values with integer keys.

Keep that idea in mind, knowing that an array is really an object helps you gain intuition for WAT is happening.

Okay…so I know how to type good, but can i do the adding thingy?

Well…let’s see.

javascript wat presentation

https://www.ecma-international.org/ecma-262/6.0/Ecma_RVB-003.jpg

The addition operator in JavaScript (as formally defined in 11.6.1 of the ECMA spec) is the following:

The production AdditiveExpression : AdditiveExpression + MultiplicativeExpression is evaluated as follows: 1. Let lref be the result of evaluating AdditiveExpression 2. Let lval be GetValue ( lref ). 3. Let rref be the result of evaluating MultiplicativeExpression. 4. Let rval be GetValue ( rref ). 5. Let lprim be ToPrimitive ( lval ). 6. Let rprim be ToPrimitive ( rval ). 7. If Type ( lprim ) is String or Type ( rprim ) is String, then return the String that is the result of concatenating ToString ( lprim ) followed by ToString ( rprim ) 9. Return the result of applying the addition operation to ToNumber ( lprim ) and ToNumber ( rprim ). See the Note below 11.6.3 .

Oh boy that’s a lot to look through.

javascript wat presentation

https://tgimworklife.files.wordpress.com/2010/10/overwhelmed.jpg

Breaking it down, we’re just going to be calling this function GetValue on the left and right hand side of the addition operator. For the two results we get back from GetValue , we then call a function ToPrimitive . If the results of ToPrimitive on both sides are strings, just concatenate them. Otherwise, just add them (according section 11.6.3).

Alright…so what are these GetValue and ToPrimitive functions?

Per the ECMA spec, GetValue will just return the value associated with the variable passed into it (ref section 8.7.1 ). The more interesting part is what happens next.

ToPrimitive takes in an input argument and a PreferredType optional argument. The addition operation doesn’t specify a second arg to ToPrimitive , so the results are as follows:

javascript wat presentation

Basically, for all of the primitive types undefined , null , boolean , number , string , we don’t do anything and leave them as is. For everything else (ie an object), we called another function called DefaultValue on the object itself specified in section 8.12.8 of the ECMA spec.

The spec says that when DefaultValue is called with no hint (what we are doing in this case), then it behaves as if the hint were Number. In that case, we call the valueOf method on the argument of DefaultValue . If that result is a primitive value, just return that. Otherwise, we call toString on the argument! If this str is a primitive value then return it. Otherwise, throw a type error exception.

The next question is what happens when we call toString (I promise we’re almost done here). Well, according to section 9.8 of the spec, we output the following

javascript wat presentation

Okay, for an object, it says to go back to ToPrimitive and pass in a hint of String …going back, we see that calling ToPrimitive on an object with a hint (i.e. PreferredType of String ) leads us to go back to the DefaultValue method, but this time with a hint of String as well. In this case, if there exists a toString method on argument passed in, just return that string.

Whew…I think we’re done. But what does this all mean?

Well…let’s take a look at the first example in Bernhardt’s talk.

Array plus Array equals empty string..right?

Okay so, walking through our line of logic, recall that an array is of type object. What happens when I call ToPrimitive(GetValue(([])) on the empty array?

By the line of reasoning I went through above, we’ll just end up calling toString on the array. Per section 15.4.4.2 of the spec, we call join on the array with no arguments. And per section 15.4.4.5 (specifying the join operation), we just concatenate all the elements of the array separated by commas. So [].toString() = '' .

Recall that the addition operator actually does call GetValue followed by ToPrimitive on each of the operands. So we’ll end up with an expression as follows

And voila, we are done. Moving on.

Array plus Object equals uhh…why is it [object Object]?

javascript wat presentation

http://i0.kym-cdn.com/entries/icons/mobile/000/021/464/14608107_1180665285312703_1558693314_n.jpg

Try looking up Object.prototype.toString() in the ECMA spec. You’ll see that in section 15.2.4.2 , it defines that if toString is called on an object you output [object + class + ] . The class variable is determined by getting the internal class of a given object (the equivalent of calling variable.constructor.name ).

For a regular object, this is just {}.constructor.name = 'Object' . So the final toString() output on an object {} is [object Object] .

Going through the whole chain again…

Okay, this next one is very weird:

Object plus Object equals [object Object][object Object] right?

Kinda. So in some cases if you type in {} + {} into a web browser console, it will output [object Object][object Object] (it does this in the Chrome REPL and the node REPL). But for some other browsers, you’ll get NaN (e.g. Firefox). What’s going on?

It totally depends on how the individual browser implements the ECMA spec. In the first case, the browser just considers the first and second operands as objects, and calls the typical toString methods on them and concatenates the resulting strings.

But the first {} can also be interpreted as a code block which can essentially be thought of as…nothing. So our {} + {} actually boils down to +{} .

This +{} is referred to as unary addition. The main difference with unary addition is that it only works with one operand (in this case {} ) and does ToNumber(ToPrimitive(GetValue({}))) instead of a ToPrimitive(GetValue({})) call. The ToNumber operation is specified in section 9.3.1 , but I won’t go through explaining everything…because there are a lot of cases. General rules of thumb:

  • If the value looks like a number, it gets cast to a number.
  • If it is an empty string, it gets cast to 0.
  • Other truthy and falsy values get cast to 1 and 0 respectively.
  • Anything else is NaN

So let’s evaluate the original expression.

Ah so Object plus Array equals…0?

Yes! You’re getting it (at least I am hoping you get it…medium articles are not a great way to get user feedback). Let’s just walk through this quickly.

The first {} is considered a code block (this is surprisingly consistent across browsers). So, we’re now going to do unary addition on empty array.

NaNNaNNaN… WATMAN!

javascript wat presentation

http://www.dccomics.com/sites/default/files/GalleryChar_1920x1080_BM_Cv38_54b5d0d1ada864.04916624.jpg

Whee! We’re almost done. This is what we’re looking at next.

Walking through this:

  • Array(16) creates an array with 16 elements that have empty values in each slot.
  • The join call concatenates all the values of the array, appending the value passed into join ’s argument e.g. [1,2,3].join('hi') = 1hi2hi3 .
  • Lastly, we just concatenate a string ' Batman'

But what does the subtraction operation do? It looks like the 'wat' — 1 operation yields NaN .

Per section 11.6.2, we just call GetValue and then ToNumber on each of the operators. Using our previous knowledge, this will yield NaN — 1 . Per section 11.6.3 , if one of the operands of additive operators is NaN , the result is NaN .

Aha! We are done. QED (well…this isn’t a proof…but regardless, you got through the article).

Okay, I’m just going to say this: JavaScript’s type system isn’t all that bad .

Yeah, it may be annoying to deal with random errors, here and there, but this system is an incredibly intuitive way to think about programming (cue screeches of thousands of Java developers).

For example, I teach CIS197 at UPenn, and a number of my students are beginner programmers. While the curriculum in the intro to CS classes stresses Java and OCaml, JavaScript serves as a nice break from the strongly typed languages, and I am really glad to see my students amazed when they don’t have to think about making sure a specific variable is declared as an int or a specific type of object. A variable should just be something that can change . By placing restrictions on it, you’re partially defeating the purpose.

While most people think that JS’s type system is incredibly illogical, there is a reason behind the madness for nearly everything you can think of. Yes, it may be frustrating, but that is the price JS developers pay for having a language that allows you to freely interconvert between types. And yeah…I’d pay that price every day.

Yassine Moumen

DevOps Cloud

JavaScript Says WAT!

Enough making fun of languages that suck. Let’s talk about JavaScript. Gary Bernhardt

A popular pastime among programmers is to make fun of programming languages, or at least the one you choose not to use. For example, Gary Bernhardt’s 5-minute talk WAT is all about unexpected behavior, mostly in Javascript.

A brief summary of the video:

On January 12, 2012, at the CodeMash conference in a Sandusky, Ohio indoor water park, Gary Bernhardt presented a lightning talk titled WAT. Bernhardt displayed some absurd anomalies in Ruby and JavaScript. After each example, he showed a funny picture that was captioned with “WAT”. The crowd loved it. It is a classic bit. Wat has become The Aristocrats of JavaScript.

But seriously though, JavaScript?!, what’s up with this:

JavaScript does it differently, and this doesn’t mean it’s wrong:

Many of the jokes are due to the type coercion algorithms behind JavaScript’s “==” (equal sign equal sign) and “+” (plus sign) operators. The type coercion rules are complex, unmemorable, and in some cases, as you will see, wrong. That is why it is not recommend to use of “==” (equal sign equal sign). It implements ECMAScript’s Abstract Equality Comparison Algorithm. It is a can of worms that is not worth opening. it is better to use “===” (equal sign equal sign equal sign) instead. Some people do not like “===” (equal sign equal sign equal sign) because it looks 50% stupider than “==” (equal sign equal sign) which is itself twice as stupid as “=” (equal sign). Nevertheless, the correct equality operator in JavaScript is “===” (equal sign equal sign equal sign).

The empty string is a falsy value, so a sloppy equals operator might want to conflate it with false . An empty array is not falsy, yet it also compares to false . And null and undefined are falsy values, but neither compares to false .

Two empty arrays are not the same object, so they are not equal. But the second line is surprising. It appears that JavaScript is a language in which x and not x can be equal to each other, which would be a seriously laughable incompetence. This is what is happening:

An empty array is truthy, so ![] is false . The sloppy equals operator wants to compare [] and false as numbers even though neither is a number. The empty array is coerced to empty string which is coerced to zero. And false is also coerced to zero. Zero equals zero, so the answer is true .

If you want to know more about equality in JavaScript, I highly recommend giving the JavaScript-Equality-Table a look.

All of these cases should produce NaN . This is what NaN is for. Instead, because the values are not numbers, “+” (plus sign) wants to concatenate them. First it has to coerce them to strings. The Array.prototype.toString() method converts an empty array to an empty string. It would be better if it acted like JSON.stringify() and returned “[]”. The worthless Object.prototype.toString() method renders the objects as “[object Object]”. Then those strings get concatenated together.

I know this is not bad code as such, but it does not provide the expected result, thus you may see something that looks extraordinarily complicated – a usual sign of bad code – which is necessary because the simple version does not work.

If you want a more in-depth explanation of each WAT in this presentation, check out this stackoverflow response .

Why is JavaScript so often the butt of the joke?

Part of the reason is that it is a language that beginners pick up and never quite mange to learn – so they end up churning out some very bad code. It is also the case that JavaScript looks like a trivial language; this means you can get a long way without having to learn anything new so, again, the result is bad code. Many programmers think that when they see bad code in a language, then it is the language’s fault. Of course, you can see bad code in many languages. But JavaScript has a reputation for it that goes well beyond what seems reasonable.

In conclusion

This isn’t to say that all languages are equal, there are better and worse, of course. But too often I hear people ranting about a language being stupid for some decision, without bothering to find out why it was done that way, and what benefit they might get from it. To which, I say: WAT!?

Further Reading

  • https://medium.com/dailyjs/the-why-behind-the-wat-an-explanation-of-javascripts-weird-type-system-83b92879a8db
  • https://stackoverflow.com/questions/9021109/what-is-in-javascript/9021351#9021351
  • https://blog.caplin.com/2012/01/27/the-why-of-wat/
  • https://missingtoken.net/ruby/2014/11/13/the-why-of-wat-ruby-edition/
  • https://project-awesome.org/JanVanRyswyck/awesome-talks
  • https://github.com/denysdovhan/wtfjs