TBH, all those pose nothing really unexpected. It all makes sense. I was a real JS hater, too - just because I didn't understand the language and I would have laughed at those examples - until I watched "Crockford on JavaScript." It's an interesting, entertaining, educating, (quite longish) series you should treat yourself to. And just as drostie said, given the way the language was born, it's really an amazing thing. And yes, it does have ugly parts.
Bear in mind that I know very little JavaScript so I may be completely wrong or this may be a very simple observation, but isn't the confusion in the first part simply due to the printed representation of the Array prototype/object?
I seem to remember that arrays in JavaScript are in theory just objects/dicts such that:
var a = [1, 2, 3];
is equivalent to
var a = {0 : 1, 1: 2, 2: 3};
and whatever function is invoked by evaluating `a` in the console must just iterate over the sorted keys of the object, starting at key = 0 and attempting to print key + 1 until the key does not exist. So he may be setting `a[-1]` and it happily exists, but the confusion is just down to the whatever the equivalent of the `__repr__` function is for JavaScript arrays.
Yes, most of the confusion is the author's misunderstanding of how arrays work in JS, combined with his tool not showing everything he put into the array.
You're correct that arrays are objects, which means they consist key/value pairs. Keys must be strings; values can be anything. So when you say `a[0] = 3;`, JS converts that to `a["0"] = 3;` and stores `{ "0": 3 }`.
So all those "funny" examples the author provides are just variants on converting an expression to a string. For example, `a[typeof a] = 4` is equivalent to `a["object"] = 4` (or `a.object = 4`) because `typeof a` is "object".
There's one wrinkle on this, though: objects and arrays aren't exactly the same thing. Arrays are a special kind of object, as far as JS is concerned. JS maintains a special "length" property for arrays. It doesn't do that for other objects.
(The same applies to JS functions and Regexes. They're objects, but they're special kinds of objects that can do things regular objects can't.)
Yes, most of the confusion is the author's misunderstanding of how arrays work in JS, combined with his tool not showing everything he put into the array.
There is nothing in the post that shows that author doesn't know how arrays are represented internally. Moreover, whether or not he does is largely irrelevant. He shows clear examples of bad language design, and they remain such whether you're aware of the inner workings of the language or not.
JavaScript's arrays have issues that span far beyond mere "string representation". For example, you can't safely use for...in construct to iterate over items in an array.
I think you missed this bit at the beginning of the article:
"Also keep in mind that sometimes I'm playing stupid, but sometimes I'm actually stupid."
I suspect the author knows exactly how arrays work in JS and is just mucking about to demonstrate one of the "Bad Parts". This is pretty much in the same vein as the WAT video (https://www.destroyallsoftware.com/talks/wat)
> JS maintains a special "length" property for arrays. It doesn't do that for other objects. (The same applies to JS functions and Regexes. They're objects, but they're special kinds of objects that can do things regular objects can't.)
Indeed JS functions have a special `length' property too, where one can check the # of arguments specified in the function definition.
Not just the length property, but also a special array API (push, pop, etc). So there is no equivalence between an array and the simple object constructed from its keys and values, but the object would correctly represent a snapshot of the subset of array key-value pairs.
Technically, the special API is because arrays extend Array.prototype. You could create an object that does the same, and push(), pop(), etc would work.*
Try going to http://www.objectplayground.com and putting in the following code, selecting the "Show built-in objects" option, and evaluating:
*Well, they sort of work. They use and modify the "length" property, so you could see some weird behavior under some circumstances. Not recommended for production use. :-)
It describes many ridiculous things in javascript such as empty array + empty array == empty string, etc. It is also great for a good laugh to anyone who has ever written javascript or ruby.
Many of those examples also make sense when you consider what you're actually asking for.
For example, Arrays have no + operator. So []+[] requires that [] be converted to a string first. The string representation of [] is "" (although some interpreters use "[]" or "[Array]" for clarity), so []+[]==""+""=="".
Similarly, he used the example []+{}, and claimed it was [object Object]. This actually wrong (at least in Chrome); it's actually "[object Object]", a string. The reason for this is the same as the previous example.
However, there is a different reason why {}+[]==0, given that "[object Object]"+[] == "[object Object]". There turns out to be something special about {} at the beginning of a statement (It's a block, or something). Thus, {}+[] is like {};+[], where +[] causes [] to be converted to a number: 0. Compare: {}=={} (syntax error, unexpected token ==). Yes, this one is actually confusing. (However, expressions are not usually evaluated in void context.)
He also observes that ",,,,,,,,,,,,,,," is a bad representation of Array(16). It is, since the undefined in each element is important, but again, that can be solved by using an interpreter with better string generation. (Or a version of IE that doesn't attempt to be clever and just returns "[Object]" all the time).
So perhaps the moral of the story is: Yes, it's an entertaining talk, but a several of the examples break down because his interpreter is vague.
The comma operator in Javascript is a major WTF. The entire post basically comes down to a, b evaluates to b, [] coerces to string, and arrays are objects.
The only thing to really look bad is chrome, which is surprisingly easy to kill.
Same as the article, you are adding properties to a. A is an array, not an hashmap. Any index that is not a number will create a property, not a new index.
Those are only little WTFs. The fact that object-equality is being tested for, for example, is not a WTF on its own; it's a valid concern in any non-functional language (answering the important question, "will editing X affect Y?").
The fact that everything has a string representation which gives everything a natural lexicographical ordering (which is inconsistent with the value-ordering of numbers) is also not a WTF, especially because `array.sort(function (x, y) { return x - y; })` does precisely what you want extensibly. Maybe the fact that there is no `<>` operator to represent `x >= y && x <= y` (which would basically test if x.toString() == y.toString() for the general ordering) might be a WTF, if you're expecting == to be consistent with <=. But the general idea of "we're not going to try to be smart, we'll just use strings" is actually very Unix-y. The alternative is to throw errors whenever you try to sort arrays which have incompatible types -- but JS doesn't have a strong notion of types.
Don't get me wrong, I'd love it if JS were different in many ways -- especially if it were more functional, because so much of the core language is built around functional concepts. There are also now type systems which are being developed which allow for the 'duck typing' style that JS uses for everything; it would have been nice if Eich had been able to magically foresee it back when it was LiveScript.
But for a language which was a little haphazardly thrown together at first and then was haphazardly canonized by two competing companies during the Browser Wars, it's actually done remarkably well.
The point is not what "==" should do. The point is you have even two equality operators - with subtle differences - and still no way to compare two arrays by value without boilerplate, which should be trivial.
Not really no. Every object has it's prototype set to the object prototype. Which means that even if you create a new empty object, it inherits functions and values from the object protype.
var a = {};
typeof(a.hasOwnProperty) === "function"
Objects are very often used as associative arrays, quite simply becouse objects and arrays are all js has to offer. Javascript Harmony will change that though, with it's own Map type.