April 2, 2012

Four Javascript Gotchas

Just as Stevey predicted 5 years ago, Javascript is a big deal these days. It's flexible, it's fast (thanks to V8), it's familiar, and it's functional. But, it grew up in a rough neighbourhood, which is to say the internet, and it did so in the bad old days of the web. So, it's retained a few bad habits from its misspent youth.

Here are the ones that used to keep me up at night, time and time again.

Use “var”

If you fail to use the “var” keyword, your variable will end up in the global scope. I'm not sure I need to tell you why this is bad.

From MDN:

The scope of a variable declared with var is the enclosing function or, for variables declared outside a function, the global scope (which is bound to the global object).

Using var outside a function is optional; assigning a value to an undeclared variable implicitly declares it as a global variable (also a property of the global object). The difference is that a declared variable is a non-configurable property of the global object while an undeclared is configurable.

Consequently, it is recommended to always declare your variables, regardless of being in the global scope or in a function

Coming from just about any other language, this might come as unexpected. Even PHP’s default behavior is to constrain the scope of a variable declared in a function to that function. Not so for Javascript.

Put semicolons in, even when it seems optional

Some languages -- Python and Ruby spring to mind -- expect lines to end with line breaks. Each of these has some cleverness to get around issues where a line break may not be the end of a statement, such that it's seldom any problem.

Javascript is not so clever. If you're not careful and break a multiline statement in the wrong place, JS will happily insert a semicolon in for you. Just include semicolons wherever necessary and you should never have to worry.

Trailing commas in object declarations break some browsers but not others

In python, the trailing comma is a downright institution; the common use of parentheses for both tuple declaration and statement grouping means that, to declare a tuple with 1 element, the syntax (‘item’,) is a preferred shorthand (with the trailing comma indicating a sequence rather than a group).

In javascript, a trailing comma in an object declaration, i.e. {id:1, property:’test’,}, will be an error. It’s allowed in newer versions of ECMAScript, but with IE6 still lumbering around, you’d best avoid it.

”this” doesn’t mean what you probably think it means.

“this” will only ever refer to a function, which means that if you want it to refer to a "class" -- that is, a function enclosing other functions and variables -- you'll need to either enclose your functions in the constructor or use prototype.

If you’ve ever made the mistake of trying to define a "class" using the object notation, or tried to assign a function as a method from outside the constructor, you will have learned this the hard way.

Solutions

There is no substitute for learning more about Javascript’s quirks. However, I can’t rush to recommend two things that should solve, or at least alleviate, the problems discussed here.

Cross-browser libraries: You probably just thought, “jQuery,” and it is a fine library indeed. However, many utility libraries exist that provide ways of working that avoid some of the problems discussed above. Iterating using functions (as long as you use the var keyword) prevents what should be loop-only variables from escaping. Underscore.js is my favorite utility belt, but choose one you like and leave the browser differences to someone else.

Coffeescript: Coffeescript is Javascript re-written by Ruby enthusiasts. Whatever you think about the syntax (I like it, some don’t), you will come to appreciate the preprocessor’s proactiveness when it comes to fixing errors like these before they come up. In fact, in Coffeescript, most of these things are not even errors, so you don’t have to feel bad about leaving off a semicolon here or there.