Chapter 2. Comments

Comments are often the least popular part of coding. They’re dangerously close to documentation, which is the last thing any developer wants to spend time doing. However, comments are incredibly important for the overall maintainability of the code. Opening a file without any comments may seem like a fun adventure, but when there are deadlines to meet, this task turns into torture. Appropriately written comments help tell the story of code, allowing other developers to drop into a part of the story without needing to hear the beginning. Style guidelines don’t always cover commenting styles, but I consider them important enough to warrant their own section.

JavaScript supports two different types of comments: single-line and multiline.

Single-Line Comments

Single-line comments are created by using two slashes and end at the end of the line:

// Single-line comment

Many prefer to include a space after the two slashes to offset the comment text. There are three ways in which a single-line comment is used:

  • On its own line, explaining the line following the comment. The line should always be preceded by an empty line. The comment should be at the same indentation level as the following line.

  • As a trailing comment at the end of a line of code. There should be at least one indent level between the code and the comment. The comment should not go beyond the maximum line length. If it does, then move the comment above the line of code.

  • To comment out large portions of code (many editors automatically comment out multiple lines).

Single-line comments should not be used on consecutive lines unless you’re commenting out large portions of code. Multiline comments should be used when long comment text is required.

Here are some examples:

// Good
if (condition) {

    // if you made it here, then all security checks passed
    allowed();
}

// Bad: No empty line preceding comment
if (condition) {
    // if you made it here, then all security checks passed
    allowed();
}

// Bad: Wrong indentation
if (condition) {

// if you made it here, then all security checks passed
    allowed();
}

// Good
var result = something + somethingElse;    // somethingElse will never be null

// Bad: Not enough space between code and comment
var result = something + somethingElse;// somethingElse will never be null

// Good
// if (condition) {
//    doSomething();
//    thenDoSomethingElse();
// }

// Bad: This should be a multiline comment
// This next piece of code is quite difficult, so let me explain.
// What you want to do is determine whether the condition is true
// and only then allow the user in. The condition is calculated
// from several different functions and may change during the
// lifetime of the session.
if (condition) {
    // if you made it here, then all security checks passed
    allowed();
}

Multiline Comments

Multiline comments are capable of spanning multiple lines. They begin with /* and end with */. Multiline comments aren’t required to span multiple lines; that choice is up to you. The following are all valid multiline comments:

/* My comment */

/* Another comment.
This one goes to two lines. */

/*
Yet another comment.
Also goes to a second line.
*/

Although all of these comments are technically valid, I prefer the Java-style multiline comment pattern. The Java style is to have at least three lines: one for the /*, one or more lines beginning with a * that is aligned with the * on the previous line, and the last line for */. The resulting comment looks like this:

/*
 * Yet another comment.
 * Also goes to a second line.
 */

The result is a more legible comment that is visually aligned on the left to an asterisk. IDEs such as NetBeans and Eclipse will automatically insert these leading asterisks for you.

Multiline comments always come immediately before the code that they describe. As with single-line comments, multiline comments should be preceded by an empty line and should be at the same indentation level as the code being described. Here are some examples:

// Good
if (condition) {

    /*
     * if you made it here, 
     * then all security checks passed
     */
    allowed();
}

// Bad: No empty line preceding comment
if (condition) {
    /*
     * if you made it here, 
     * then all security checks passed
     */
    allowed();
}

// Bad: Missing a space after asterisk
if (condition) {

    /*
     *if you made it here, 
     *then all security checks passed
     */
    allowed();
}

// Bad: Wrong indentation
if (condition) {

/*
 * if you made it here, 
 * then all security checks passed
 */
    allowed();
}

// Bad: Don't use multiline comments for trailing comments
var result = something + somethingElse;    /*somethingElse will never be null*/

Using Comments

When to comment is a topic that always fosters great debate among developers. The general guidance is to comment when something is unclear and not to comment when something is apparent from the code itself. For example, the comment in this example doesn’t add any understanding to the code:

// Bad

// Initialize count
var count = 10;

It’s apparent from just the code that count is being initialized. The comment adds no value whatsoever. If, on the other hand, the value 10 has some special meaning that you couldn’t possibly know from looking at the code, then a comment would be very useful:

// Good

// Changing this value will make it rain frogs
var count = 10;

As implausible as it may be to make it rain frogs by changing the value of count, this is an example of a good comment, because it tells you something that you otherwise would be unaware of. Imagine how confused you would be if you changed the value and it started to rain frogs…all because a comment was missing.

So the general rule is to add comments where they clarify the code.

Difficult-to-Understand Code

Difficult-to-understand code should always be commented. Depending on what the code is doing, you may use one multiline comment, several single comments, or some combination thereof. They key is to bring some understanding of the code’s purpose to someone else. For example, here’s some code from the YUI library’s Y.mix() method:

// Good

if (mode) {

    /*
     * In mode 2 (prototype to prototype and object to object), we recurse
     * once to do the proto to proto mix. The object to object mix will be
     * handled later on.
     */
    if (mode === 2) {
        Y.mix(receiver.prototype, supplier.prototype, overwrite,
                whitelist, 0, merge);
    }

    /*
     * Depending on which mode is specified, we may be copying from or to
     * the prototypes of the supplier and receiver.
     */
    from = mode === 1 || mode === 3 ? supplier.prototype : supplier;
    to   = mode === 1 || mode === 4 ? receiver.prototype : receiver;

    /*
     * If either the supplier or receiver doesn't actually have a
     * prototype property, then we could end up with an undefined from
     * or to. If that happens, we abort and return the receiver.
     */
    if (!from || !to) {
        return receiver;
    }
} else {
    from = supplier;
    to   = receiver;
}

The Y.mix() method uses constants to determine how to proceed. The mode argument is equivalent to one of those constants, but it’s hard to understand what each constant means just from the numeric value. The code is commented well, because it explains what otherwise appear to be complex decisions.

Potential Author Errors

Another good time to comment code is when the code appears to have an error. Teams often get bitten by well-meaning developers who find some code that looks problematic, so they fix it. Except that the code wasn’t the source of a problem, so “fixing” it actually creates a problem that needs to be tracked down. Whenever you’re writing code that could appear incorrect to another developer, make sure to include a comment. Here’s another example from YUI:

while (element &&(element = element[axis])) { // NOTE: assignment
    if ( (all || element[TAG_NAME]) && 
       (!fn || fn(element)) ) {
            return element;
    }
}

In this case, the developer used an assignment operator in the while loop control condition. This isn’t standard practice and will typically be flagged by linting tools as a problem. If you were unfamiliar with this code and came across this line without a comment, it would be easy to assume that this was an error, and the author meant to use the equality operator == instead of the assignment operator =. The trailing comment on that line indicates the use of the assignment operator is intentional. Now any other developer who comes along and reads the code won’t be likely to make a bad “fix.”

Browser-Specific Hacks

JavaScript developers are often forced to use code that is inefficient, inelegant, or downright dirty to get older browsers to work correctly. This behavior is actually a special type of potential author error: code that isn’t obviously doing something browser-specific may appear to be an error. Here’s an example from the YUI library’s Y.DOM.contains() method:

var ret = false;

if ( !needle || !element || !needle[NODE_TYPE] || !element[NODE_TYPE]) {
    ret = false;
} else if (element[CONTAINS])  {
    // IE & SAF contains fail if needle not an ELEMENT_NODE 
    if (Y.UA.opera || needle[NODE_TYPE] === 1) { 
        ret = element[CONTAINS](needle);
    } else {
        ret = Y_DOM._bruteContains(element, needle); 
    }
} else if (element[COMPARE_DOCUMENT_POSITION]) { // gecko
    if (element === needle || !!(element[COMPARE_DOCUMENT_POSITION](needle) & 16)) { 
        ret = true;
    }
}

return ret;

Line 6 of this code has a very important comment. Even though Internet Explorer and Safari both include the contains() method natively, the method will fail if needle is not an element. So the method should be used only if the browser is Opera or needle is an element (nodeType is 1). The note about the browsers, and also why the if statement is needed, not only ensures that no one will change it unexpectedly in the future, but allows the author to revisit this code later and realize that it may be time to verify whether newer versions of Internet Explorer and Safari show the same issue.

Documentation Comments

Documentation comments aren’t technically part of JavaScript, but they are a very common practice. Document comments may take many forms, but the most popular is the form that matches JavaDoc documentation format: a multiline comment with an extra asterisk at the beginning (/**) followed by a description, followed by one or more attributes indicated by the @ sign. Here’s an example from YUI:

/**
Returns a new object containing all of the properties of all the supplied
objects. The properties from later objects will overwrite those in earlier
objects.

Passing in a single object will create a shallow copy of it. For a deep copy,
use `clone()`.

@method merge
@param {Object} objects* One or more objects to merge.
@return {Object} A new merged object.
**/
Y.merge = function () {
    var args   = arguments,
        i      = 0,
        len    = args.length,
        result = {};

    for (; i < len; ++i) {
        Y.mix(result, args[i], true);
    }

    return result;
};

The YUI library uses its own tool called YUIDoc to generate documentation from these comments. However, the format is almost exactly the same as the library-agnostic JSDoc Toolkit, which is widely used on open source projects as well as within Google. The key difference between YUIDoc and JSDoc Toolkit is that YUIDoc supports both HTML and Markdown in documentation comments, whereas JSDoc Toolkit supports only HTML.

It is highly recommended that you use a documentation generator with your JavaScript. The format of the comments must match the tool that you use, but the JavaDoc-style documentation comments are well supported across many documentation generators. When using documentation comments, you should be sure to document the following:

All methods

Be sure to include a description of the method, expected arguments, and possible return values.

All constructors

Comments should include the purpose of the custom type and expected arguments.

All objects with documented methods

If an object has one or more methods with documentation comments, then it also must be documented for proper documentation generation.

Of course, the exact comment format and how comments should be used will ultimately be determined by the documentation generator you choose.