Sunday, October 4, 2009

Enlighten me on JavaScript

I am learning JavaScript because it will likely be a useful language for me in the future (it is a very popular language, and since I don't really want to move back to Silicon Valley it's hard to find jobs using languages I like). And there are things I just don't quite understand about the way it was designed, both about the language and about the DOM. I am open to the fact that there are things I just don't know about; I'm just a beginner. If anyone has good answers to any of these (meaning ways to make programming simple things as easy as they should be), let me know.

1. Why did they make the string concatenation operator the same as the numerical addition operator? In C++ using many string classes they're the same. But in C++ variables have types, so you know exactly what you're getting by looking at the types. In Perl variables don't (usually) have types, but the set of operators for numerical and string operations are completely different, so you know exactly what you're getting by looking at the operators. In JavaScript if you aren't sure what your variables' types are you have to do coerce them (unary + and concatenating an empty string are the easiest ways I know of). It's ugly and inconvenient, so people aren't as careful as they should be, and it bites them.

And, yeah, I have some idea why they may have done it. They wanted to keep all the C-style operators intact, and they use up so many symbols that you have to overload them. I don't think it's all that good of an excuse. It's nice that C-style syntax is familiar to lots of people, but honestly, who cares about bitwise operations in JavaScript? Few enough people that they could have just been made functions. As a C programmer learning JavaScript, trust me, it would not have been an obstacle to my learning the language.

2. How do you "pass-by-value" into anonymous functions? Yeah, closures are wonderful, in some unusual cases. But what if I want to just use the value? This is arguably more common than actually wanting a closure; for example, when creating anonymous event handlers that use the iterating variable of a for loop. To do this relatively simple thing you can create an external function taking the values as arguments and returning a function enclosing the copied arguments. Or you can use (function(a){return function(){doSomethingWith(a)};})(i). Which is, as Geordi La Forge says of Data's poetry, "clever". What it isn't is readable or easy to understand. Especially when so many of the people writing JavaScript aren't CS majors.

EDIT: One more note about this. This would seem to be a general problem in languages with closures, but it's not really so bad in some others. I don't know most of the languages that seem to generate most of the closure chatter (Lisp, Python, and the .NET languages) well enough to quickly test this, but I do know Perl, which does indeed have closures. Perl's lexical variables have block-level scope and extent, so you can enclose the iterating variable's current value by declaring one within the loop and using that in your anonymous function. JavaScript only has function-level scope/extent, so you can't do that -- you have to replicate the functionality with an immediately-executed anonymous function. Kool-Aid drinkers say it's a testament of JS's flexibility; I say it's a pain in the ass. As for the other languages, the Internet knows! Reportedly modern VBScript has block-scope variables with function extent, which strikes me as bizarre; C# does it right (here, as usual, doing it right means doing it like Perl). Python doesn't have block-level scope, and Lisp lets you have any kind of scope/extent you want; a let variable would give you what you wanted as long as the let was inside the loop. C and C++, of course, do it right, but they don't have closures. So it's a mixed bag.

3. Using the nice, proper DOM event functions, how do you replace one anonymous event handler with another? Why, addEventListener and removeEventListener, of course! But removeEventListener requires a reference to the handler you want to remove. So all those nice anonymous ones I just created? Useless. I have to keep track of them. It's nice that this makes it really easy to have multiple handlers for every event. But, again, that is an unusual thing to need. They've taken care of the unusual need and not the normal one. Yeah, there's the older onclick style, but I'm pretty sure it's deprecated now.

4. Why is there no call to clear all the children of a DOM node? Instead you have to write your own loop for it. It's not hard to write but it's a waste of time and an opportunity to make mistakes.

No comments: