I've had a few beers, so I'm just going to come out and say it: JavaScript is a terrible language. The best thing it has going for it is that it's Turing Complete.
"But wait!" you cry, "it's dynamic! It has lexical scope and lambdas! CLOSURES!" Too bad tail call elimination isn't in the spec. Or any kind of optimization on continuations or recursions. Yay running out of stack, tons of fun.
I'll write a book called "JavaScript: the Best Part" and it will be one page long with "Parenscript is the best part of JavaScript" printed on it, with "(pray you don't end up 10-feet deep in a call stack)" in smaller type underneath.
Maybe I should lay off the India pale ales and comments.
edit: I had to use JavaScript for something a few weeks back, it was like being hit on the head with a hammer wrapped in a damp cloth. Let me show you what I mean: http://emgio.com/wow.png There are so many things wrong with this that I had to take a picture, which I now show to people whenever they try to argue in JavaScript's defense. The blue text is interpreter input and black is the return.
Actually, JavaScript makes a fun benchmark race I guess, just because it's so ridiculously hard to write an optimized interpreter for.
You should learn some more javascript. The language itself is pretty sweet. Individual implementations vary.
Your image just shows you don't understand very much about the language. It's not "wrong" once you understand what it's doing and why. Show it to anyone who understands what is happening, and you'll look quite foolish. It's not massively complex once you read "Javascript: The definitive guide (O'Reily)" - the best book on js by a mile.
var obj1 = {};
// var doesn't return anything, so the interpreter shows 'undefined'.
var obj2 = {};
// same again
obj1 == obj2;
// Well no, they're different objects. So you'll get false
var thing = {};
//
thing[obj1] = "hi";
// OK this is an odd thing to want to do, but you're doing it anyway.
// You're using an *object* (obj1), as a key.
// The js thinks you're idiotic, but complies by calling the .toString() method,
// and gets "[object Object]" or similar by default.
// (You're free to override that on your object).
thing[obj2]
// Once again, you're using an object as a key
// and acting surprised that js has changed it into a string.
// So, you created an object and set thing["object Object"] = "hi"
So instead of "Wow! js is retarded", my response to that code would be "Why is he trying to use objects as keys? and why is he surprised when js converts them to strings?"
I recommend the above book to clear up things like this.
Read it again, the problem is that it accepts it silently and does not indicate any sort of irregular behavior in an operation that shouldn't work that way. It just does it and then fails weirdly in the future.
I fully understand how equality works in JavaScript (especially after making the mistake pictured.)
Also, the existence of an "===" operator should be troubling. Many people writing JS don't even know it exists.
edit: when you extend your reply in a large way, please append it with "edit:" or just make a new reply, thanks :]
Why shouldn't it work that way??? It's silently doing type conversion for you - from an object to a string. That's desired behavior. Just as most languages presented with "foo"+12 would silently convert 12 to a string via the toString() method.
What way do you think it should work? :/
An example of more sane usage:
>>> var myv={}
>>> var foo={toString:function(){return "12"}}
>>> myv[foo]=34
34
>>> myv[12]
34
>> "Also, the existence of an "===" operator should be troubling. Many people writing JS don't even know it exists."
You can't fault a language because some people don't make the effort to learn it properly.
This is the main problem I have with it; it's a very dynamic language but in a totally dangerous way. It should hash based on an object's identity or something; as it stands, there's no way to do that in JS without bolting your own junk on top, as a result you can't do real object<->object associations in JS.
Python for example has well-defined and useful behavior when you shove something into a dict type as a key, for strings it will hash based on the string value, for some other things it will uses identity, etc., and you can overload it (which you can in JS too of course, as you showed.)
maybe the default toString() should be a unique ID, as it is in for example Java, but it's not really a big deal.
How often do you need object A->object B associations like that? Far easier to just put a pointer in all the object As to point to object Bs, and then put the object A's in an object/array.
Your use case is not something I've ever needed to be honest, and if you need it, it's simple to build it out yourself. For example, in an object constructor, just replace the toString() to return a unique ID for that object. A line of code :/
It's only dangerous when you don't understand what is happening. Why didn't you research why your image example was confusing you? As I say, read the book.
How often do you need object A->object B associations like that? Far easier to just put a pointer in all the object As to point to object Bs
This gives us an equivalent mapping, but unfortunately it alters the original object by adding a property to it. This sucks for two reasons; one is that the names might clash with a property that something else has set on that object, so you end up creating terrible names to avoid collisisions like someObject._prviate_associatedOtherObject or something, and then you have to make sure to destroy it when appropriate. It gets more hairy if you need multiple relations between the same objects. The other problem is that when you enumerate an object, now that property will show up. Gross. Yes, I know about the boilerplate you use to make enumerations in JS safe; my argument is that JS sucks as a language, and the necessity of stuff like this contributes to it.
For example, in an object constructor, just replace the toString() to return a unique ID for that object. A line of code :/
The Cappuccino/Objective-J guys at 280North have to do something similar (grep for OBJECT_COUNT++ in the source to see what I mean) in order to add identity to Obj-J objects.. but what if you didn't instantiate the object yourself? And I think this is the case where you'd be most likely to want to perform a mapping on an opaque object.
Sorry I'm replying to my own comment here, I don't have to time to wait for the next exponential decay on the reply button showing up before I have to leave. I'm actually replying to axod's comment on this same level.
Well here's an example, I have an AJAX instant messenger app. Due to the protocol it talks on, multiple users may have the same name (a reasonable request, I think.) When a contact on a user's buddy list connects, the JS library in charge of talking to the server passes an opaque ChatUser object (or whatever) to any registered callbacks. So, I write a second set of JS stuff to manage the GUI, like the window for the buddy list, etc., and register it to receive the callbacks from the protocol manager. When I get a user that connects, for example, I should probably create an html span with that user's name and away status in the div that holds the buddy list.
Now, when a buddy changes his/her away state, the protocol manager will tell the registered callbacks that a ChatUser has changed status (or you can register for a callback on the ChatUser object itself, either works.) We need to change the status message in that user's span. But how do you find the span we need to modify? The ChatUser object is mostly opaque except for a few documented calls we can make on it (getName, getStatus, etc). Setting new properties on it is probably a bad idea, since we don't know what the original library is going to be doing with it.
In another language you can just associate the span's identity with the ChatUser through a map or dictionary. But you can't associate based on identity in JS, so you're left setting some crazy property on the ChatUser instance and hoping it doesn't collide or cause problems. We can't base it on the ChatUser's name, because what if there are multiple Joe Browns in the contact list?
It's a contrived example, but I hope it illustrates the importance of associations. There are multiple workarounds for this situation. But they aren't elegant, which is why I think JS sucks :]
1. You would keep a pointer to the span, in each ChatUser object.
2. You would have *some* unique ID passed from server->client
to identify which user its talking about. A session ID say.
this could be used to lookup the ChatUser object.
>> "It's a contrived example, but I hope it illustrates the importance of associations. There are multiple workarounds for this situation. But they aren't elegant, which is why I think JS sucks :]"
Nope, and I actually think your proposed method - mapping ChatUser->span is incredibly ugly and inelegant. Horrible design. A ChatUser object should know what UI elements it is in control of directly.
Why? The original library does not deal with GUI at all. The ChatUser object does not need to know what GUI HTML elements it's associated with. One component of a piece of software extending another should not have to tamper with the original; this is just bad design in general, not OO or any specific flavor.
Axod may have overreached by saying "most languages". However, you overreach as well by saying "the minority" (though at least you add the qualifier "I'd expect".)
What Axod perhaps should have said is "most languages that support automatic type coercion."
We could have a flamewar all day about whether or not type coercion is a good or bad thing. And, actually, tumult's whole complaint could be summed up as type coercion is bad, and I don't get that object literals are different from string literals.
Many languages with type coercion, where objects can be converted to a string via a toString method of some sort, behave the same as Javascript. At most, like php, they log a warning or notice of some sort.
Personally, I prefer type coercion to throwing errors, and I prefer loose types to static types. Apparently, tumult doesn't, to the point of whining about the programming language that is the lingua franca of the web. To each his own.
No, I'm sure it's the minority. I was just being polite. :-) "Today's" programming languages are a minority too. Just think of all the ones that came and went in the 60s, 70, and 80s. Most of those were ones that wouldn't let you do "foo" + 12 as the OP said, i.e. you couldn't apply the plus operator to a string and an integer and have the integer coerced to a string automatically. It's clearly the minority that would do that, and a small minority at that.
awk and perl handle "foo" + 12, but they coerce "foo" to an integer, which is 0, and then add 12.
(Note, C lets you do "foo" + 12 but it isn't coercing 12 to a string, instead it's adding 12 to the address of the string "foo", e.g. "0123456789abcdef"[nibble].)
It would be interesting to enumerate those that do treat "foo" + 12 as if it was written "foo" + "12".
I think you miss the point. Some tools are made for precision while others are made for maximum functionality. The scalpel vs the Swiss Army Knife if you will.
Javascript is horrible in many ways. It really wasn't even designed per se. It's just a mismash of hacks that Netscape put together with a few more hacks tacked on after the fact. But while that makes it messy it also makes it amazingly flexible.
I didn't say it wasn't useful or popular. Just that it sucks! If it had just a few more things, it would be a lot easier to layer stuff on top of it, but we're kind of stuck with it now.
No I'm totally with you, AS3 and C# are way better languages than JS. The CLR (and JVM, too) are all good ideas, I think that's what JS should have been instead of a weirdly dynamic C-syntax language with some useless prototype extension bolted on top (among countless other problems.) But JS, like most of the web technologies we're stuck with, weren't so much designed as they were a series of hacks layered on.. series of tubes.. anyway, I'm preaching to the choir I'm sure.
Silverlight is actually a lot better than Flash in most ways that I've found, too bad it's not installed everywhere like Flash is. I would make some comment about MS being evil, but I think they're about on par with Adobe these days (except they still seem to employ engineers occasionally.)
I think you should step back, and go read "Javascript: The definitive guide". Also, for a good explanation of prototypical inheritance (Which is far from useless if you understand it), checkout the Douglas Crockford lectures (Vids on yahoo).
Or read javascript: the good parts, it's one of the two reasons I'm a happy javascripter. (The other is that I can restrict myself to ff3.5 which not many people will be able to)
You can bitch about how javascript sucks, and refuse to use it, or you can man up and write programs in the language that every web browser supports. Seems like a pretty easy choice to me.
Yay running out of stack, tons of fun.
Why aren't you using setTimeout to work around that limitation?
Maybe I should lay off the India pale ales and comments.
This continues to be pretty much the best JavaScript reference on the web.