Monday, August 15, 2011

In JavaScript, curly brace placement matters: An example


If you’ve been working with JavaScript very long, you probably know that you should format curly braces in JavaScript code a certain way. In fact, if you’ve watched my TekPub series, Mastering jQuery, you’ve heard me stop James and remind him that at the beginning of nearly every episode.
However, you’re less likely to have seen a clear example of why this matters or why you should care. Even when you hear advice from a trusted source, it can be difficult to heed that advice if it seems like hearsay or convention for the sake of convention.
While I was working on my recent post about extracting data objects from HTML structures, it occurred to me that some of its example code presented a great learning opportunity regarding this topic. So, I want to take advantage of that opportunity to show you a concrete example of how placing your braces on the wrong line can break your JavaScript code.

Allman, K&R, and you

The specific part of the previous post that I want to talk about is this:
return {
  id: $item.data('id'),
  text: $item.text()
};
Notice how the opening brace in the object literal is on the same line as thereturn statement.
Placing opening braces on the same line as their corresponding control statements like that is called K&R style. Unlike most differences in coding style – most amounting to personal preference – using K&R style braces in JavaScript is important for an objective reason.
That reason is well-illustrated by looking at the alternative style in this case. That alternative, Allman style, is a style that’s more common in languages like C#. Allman style braces are placed alone, at the beginning of the line immediately aftera control statement.
Modifying the previous code to use Allman style braces would look like this:
return
{
  id: $item.data('id'),
  text: $item.text()
};
That code is now broken. Though you can usually get away with using Allman style braces in JavaScript, returning object literals is an example of when you cannot.

JavaScript semicolon insertion can ruin your day

The culprit here is JavaScript’s infamous semicolon insertion feature. A JavaScript interpreter will parse return\n as a complete statement, assume that you forgot a semicolon at the end, and then treat it as return;\n instead.
In other words, when you write this:
return
{
  id: $item.data('id'),
  text: $item.text()
};
It’s actually interpreted as if you had written this:
return; // Waiter, I didn't order this semicolon!
{
  id: $item.data('id'),
  text: $item.text()
};
The insidious result is that almost all browsers will allow the code to execute, but the prematurely terminated return statement will return undefined instead of the object you’d expect. No syntax error, no warning; just a chunk of “working” code that behaves inexplicably.

Conclusion

Since this problem manifests itself as an undefined return value, you can imagine how painful it can be to trace that back to an artifact of where the curly brace is located. Unless you’re already aware of the semicolon insertion trap, brace placement is usually the last thing that you’d suspect to be the culprit in these situations.
The problem would have been even worse in the larger example that this code excerpt was extracted from. The object literal’s location within the .map() call would have obfuscated the root issue even farther since “mapping” a series of undefined return values would simply result in an empty array.
Key takeaway? Always use K&R style braces in JavaScript, even if it’s not the style you prefer in other languages.
Allman braces bring zero objective value to the table. Using them out of personal preference isn’t worth the mental overhead of consistently remembering that they break when returning object literals, nor the debugging morass that will inevitably crop up when you aren’t paying close attention and muscle memory takes over.