Chapter 1. Basic Formatting

At the core of a style guide are basic formatting rules. These rules govern how the code is written at a high level. Similar to the ruled paper used in schools to teach writing, basic formatting rules guide developers toward writing code in a particular style. These rules often contain information about syntax that you may not have considered, but every piece is important in creating a coherent piece of code.

Indentation Levels

The first decision to be made about your JavaScript style guidelines (and indeed, about those of most languages) is how to handle indentation. This is one of those topics on which debates can last for hours; indentation is about as close to religion as software engineers get. However, it is quite important to establish indentation guidelines up front, lest developers fall into the classic problem of reindenting every file they open before starting to work. Consider a file that looks like this (indentation has been intentionally changed for demonstration purposes):

if (wl && wl.length) {
            for (i = 0, l = wl.length; i < l; ++i) {
         p = wl[i];
         type = Y.Lang.type(r[p]);
         if (s.hasOwnProperty(p)) { if (merge && type == 'object') {

    Y.mix(r[p], s[p]);
} else if (ov || !(p in r)) {
                    r[p] = s[p];
                }
            }
        }
    }

Just looking at this code quickly is difficult. The indentation isn’t uniform, so it appears that the else applies to the if statement on the first line. However, closer inspection reveals that the else actually applies to the if statement on line 5. The most likely culprit is a mixture of indentation styles from several different developers. This is precisely why indentation guidelines exist. Properly indented, this code becomes much easier to understand:

if (wl && wl.length) {
    for (i = 0, l = wl.length; i < l; ++i) {
        p = wl[i];
        type = Y.Lang.type(r[p]);
        if (s.hasOwnProperty(p)) {
            if (merge && type == 'object') {
                Y.mix(r[p], s[p]);
            } else if (ov || !(p in r)) {
                r[p] = s[p];
            }
        }
    }
}

Ensuring proper indentation is the first step—this particular piece of code has other maintainability issues discussed later in this chapter.

As with most style guidelines, there is no universal agreement on how to accomplish indentation in code. There are two schools of thought:

Use tabs for indentation

Each indentation level is represented by a single tab character. So indents of one level are one tab character, second-level indentation is two tab characters, and so on. There are two main advantages to this approach. First, there is a one-to-one mapping between tab characters and indentation levels, making it logical. Second, text editors can be configured to display tabs as different sizes, so developers who like smaller indents can configure their editors that way, and those who like larger indents can work their way, too. The main disadvantage of tabs for indentation is that systems interpret them differently. You may find that opening the file in one editor or system looks quite different than in another, which can be frustrating for someone looking for consistency. These differences, some argue, result in each developer looking at the same code differently, and that isn’t how a team should operate.

Use spaces for indentation

Each indentation level is made up of multiple space characters. Within this realm of thinking, there are three popular approaches: two spaces per indent, four spaces per indent, and eight spaces per indent. These approaches all can be traced back to style guidelines for various programming languages. In practice, many teams opt to go with a four-space indent as a compromise between those who want two spaces and those who want eight spaces. The main advantage of using spaces for indentation is that the files are treated exactly the same in all editors and all systems. Text editors can be configured to insert spaces when the Tab key is pressed. That means all developers have the same view of the code. The main disadvantage of using spaces for indentation is that it is easy for a single developer to create formatting issues by having a misconfigured text editor.

Though some may argue that one indentation approach or another is superior, it all boils down to a matter of preference within the team. For reference, here are some indentation guidelines from various style guides:

  • The jQuery Core Style Guide specifies indents as tabs.

  • Douglas Crockford’s Code Conventions for the JavaScript Programming Language specifies indents as four spaces.

  • The SproutCore Style Guide specifies indents as two spaces.

  • The Google JavaScript Style Guide specifies indents as two spaces.

  • The Dojo Style Guide specifies indents as tabs.

I recommend using four spaces per indentation level. Many text editors have this level as a default if you decide to make the Tab key insert spaces instead. I’ve found that two spaces don’t provide enough visual distinction for my eyes.

Note

Even though the choice of tabs or spaces is a preference, it is very important not to mix them. Doing so leads to horrible file layout and requires cleanup work, as in the very first example in this section.

Statement Termination

One of the interesting, and most confusing, aspects of JavaScript is that statements may be terminated either with a newline or with a semicolon. This breaks from the tradition of other C-like languages such as C++ and Java, which require semicolons. Both of the following examples are therefore valid JavaScript.

// Valid
var name = "Nicholas";
function sayName() {
    alert(name);
}

// Valid but not recommended
var name = "Nicholas"
function sayName() {
    alert(name)
}

The omission of semicolons works in JavaScript due to a mechanism known as automatic semicolon insertion (ASI). ASI looks for places in the code where a semicolon is appropriate and inserts one if not found. In many cases, ASI guesses correctly and there isn’t a problem. However, the rules of ASI are complex and difficult to remember, which is why I recommend using semicolons. Consider the following:

// Original Code
function getData() {
    return
    {
        title: "Maintainable JavaScript",
        author: "Nicholas C. Zakas"
    }
}

// The way the parser sees it
function getData() {
    return;
    {
        title: "Maintainable JavaScript",
        author: "Nicholas C. Zakas"
    };
}

In this example, the function getData() is intended to return an object containing some data. However, the newline after return causes a semicolon to be inserted, which causes the function to return undefined. The function can be fixed by moving the opening brace on to the same line as return.

// Works correctly, even without semicolons
function getData() {
    return {
        title: "Maintainable JavaScript",
        author: "Nicholas C. Zakas"
    }
}

There are scenarios where ASI may be applied, and I’ve found limiting ASI to help reduce errors. The errors are typically caused by misunderstanding how ASI works and assuming that a semicolon will be inserted when it will not. I have found that many developers, especially inexperienced ones, have an easier time using semicolons than omitting them.

Semicolon usage is recommended by Douglas Crockford’s Code Conventions for the JavaScript Programming Language (hereafter referred to as “Crockford’s Code Conventions”), the jQuery Core Style Guide, the Google JavaScript Style Guide, and the Dojo Style Guide. Both JSLint and JSHint will warn by default when semicolons are missing.

Line Length

Closely related to the topic of indentation is line length. Developers find it hard to work on code in which the lines are long enough to require horizontal scrolling. Even with today’s large monitors, keeping line length reasonable greatly improves developer productivity. Code convention documents for many languages prescribe that lines of code should be no longer than 80 characters. This length comes from a time when text editors had a maximum of 80 columns in which to display text, so longer lines would either wrap in unexpected ways or disappear off the side of the editor. Today’s text editors are quite a bit more sophisticated than those of 20 years ago, yet 80-character lines are still quite popular. Here are some common line length recommendations:

  1. Code Conventions for the Java Programming Language specifies a line length of 80 characters for source code and 70 characters for documentation.

  2. The Android Code Style Guidelines for Contributors specifies a line length of 100 characters.

  3. The Unofficial Ruby Usage Guide specifies a line length of 80 characters.

  4. The Python Style Guidelines specifies a line length of 79 characters.

Line length is less frequently found in JavaScript style guidelines, but Crockford’s Code Conventions specifies a line length of 80 characters. I also prefer to keep line length at 80 characters.

Line Breaking

When a line reaches the maximum character length, it must be manually split into two lines. Line breaking is typically done after an operator, and the next line is indented two levels. For example (indents are four spaces):

// Good: Break after operator, following line indented two levels
callAFunction(document, element, window, "some string value", true, 123, 
        navigator);

// Bad: Following line indented only one level
callAFunction(document, element, window, "some string value", true, 123, 
    navigator);

// Bad: Break before operator
callAFunction(document, element, window, "some string value", true, 123
        , navigator);

In this example, the comma is an operator and so should come last on the preceding line. This placement is important because of ASI mechanism, which may close a statement at the end of a line in certain situations. By always ending with an operator, ASI won’t come into play and introduce possible errors.

The same line-breaking pattern should be used for statements as well:

if (isLeapYear && isFebruary && day == 29 && itsYourBirthday &&
        noPlans) {

    waitAnotherFourYears();
}

Here, the control condition of the if statement is split onto a second line after the && operator. Note that the body of the if statement is still indented only one level, allowing for easier reading.

There is one exception to this rule. When assigning a value to a variable, the wrapped line should appear immediately under the first part of the assignment. For example:

var result = something + anotherThing + yetAnotherThing + somethingElse +
             anotherSomethingElse;

This code aligns the variable anotherSomethingElse with something on the first line, ensuring readability and providing context for the wrapped line.

Blank Lines

An often overlooked aspect of code style is the use of blank lines. In general, code should look like a series of paragraphs rather than one continuous blob of text. Blank lines should be used to separate related lines of code from unrelated lines of code. The example from the earlier section Indentation Levels is perfect for adding some extra blank lines to improve readability. Here’s the original:

if (wl && wl.length) {
    for (i = 0, l = wl.length; i < l; ++i) {
        p = wl[i];
        type = Y.Lang.type(r[p]);
        if (s.hasOwnProperty(p)) {
            if (merge && type == 'object') {
                Y.mix(r[p], s[p]);
            } else if (ov || !(p in r)) {
                r[p] = s[p];
            }
        }
    }
}

And here is the example rewritten with a few blank lines inserted:

if (wl && wl.length) {

    for (i = 0, l = wl.length; i < l; ++i) {
        p = wl[i];
        type = Y.Lang.type(r[p]);

        if (s.hasOwnProperty(p)) {

            if (merge && type == 'object') {
                Y.mix(r[p], s[p]);
            } else if (ov || !(p in r)) {
                r[p] = s[p];
            }
        }
    }
}

The guideline followed in this example is to add a blank line before each flow control statement, such as if and for. Doing so allows you to more easily read the statements. In general, it’s a good idea to also add blank lines:

  • Between methods

  • Between the local variables in a method and its first statement

  • Before a multiline or single-line comment

  • Between logical sections inside a method to improve readability

None of the major style guides provide specific advice about blank lines, though Crockford’s Code Conventions does suggest using them judiciously.

Naming

“There are only two hard problems in Computer Science: cache invalidation and naming things.” —Phil Karlton

Most of the code you write involves variables and functions, so determining naming conventions for those variables and functions is quite important to a comprehensive understanding of the code. JavaScript’s core, ECMAScript, is written using a convention called camel case. Camel-case names begin with a lowercase letter and each subsequent word begins with an uppercase letter. For example:

var thisIsMyName;
var anotherVariable;
var aVeryLongVariableName;

Generally speaking, you should always use a naming convention that follows the core language that you’re using, so camel case is the way most JavaScript developers name their variables and functions. The Google JavaScript Style Guide, the SproutCore Style Guide, and the Dojo Style Guide all specify use of camel case in most situations.

Even with the general naming convention of camel case in place, some more specific styles of naming are typically specified.

Note

Another notation called Hungarian notation was popular for JavaScript around the year 2000. This notation involved prepending a variable type identifier at the beginning of a name, such as sName for a string and iCount for an integer. This style has now fallen out of favor and isn’t recommended by any of the major style guides.

Variables and Functions

Variable names are always camel case and should begin with a noun. Beginning with a noun helps to differentiate variables from functions, which should begin with a verb. Here are some examples:

// Good
var count = 10;
var myName = "Nicholas";
var found = true;

// Bad: Easily confused with functions
var getCount = 10;
var isFound = true;

// Good
function getName() {
    return myName;
}

// Bad: Easily confused with variable
function theName() {
    return myName;
}

The naming of variables is more art than science, but in general, you should try to make the variable names as short as possible to get the point across. Try to make the variable name indicate the data type of its value. For example, the names count, length, and size suggest the data type is a number, and names such as name, title, and message suggest the data type is a string. Single-character variable names such as i, j, and k are typically reserved for use in loops. Using names that suggest the data type makes your code easier to understand by others as well as yourself.

Meaningless names should be avoided. Names such as foo, bar, and temp, despite being part of the developer’s toolbox, don’t give any meaning to variables. There’s no way for another developer to understand what the variable is being used for without understanding all of the context.

For function and method names, the first word should always be a verb, and there are some common conventions used for that verb:

VerbMeaning
canFunction returns a boolean
hasFunction returns a boolean
isFunction returns a boolean
getFunction returns a nonboolean
setFunction is used to save a value

Following these conventions as a starting point makes code much more readable. Here are some examples:

if (isEnabled()) {
    setName("Nicholas");
}

if (getName() === "Nicholas") {
    doSomething();
}

Although none of the popular style guides go to this level of detail regarding function names, these are pseudostandards among JavaScript developers and can be found in many popular libraries.

Note

jQuery quite obviously doesn’t follow this naming convention for functions, partly due to how methods are used in jQuery, as many act as both getters and setters. For example, $("body").attr("class") returns the value of the class attribute, and $("body").attr("class", "selected") sets the value of the class attribute. Despite this, I still recommend using verbs for function names.

Constants

JavaScript had no formal concept of constants prior to ECMAScript 6. However, that didn’t stop developers from defining variables to be used as constants. To differentiate normal variables (those meant to have changing values) and constants (variables that are initialized to a value and never change), a common naming convention evolved. The convention comes from C and uses all uppercase letters with underscores separating words, as in:

var MAX_COUNT = 10;
var URL = "http://www.nczonline.net/";

Keep in mind that these are just variables using a different naming convention, so it’s still possible to overwrite the values. Normal variables and constants are easily differentiated by using this very different convention. Consider the following example:

if (count < MAX_COUNT) {
    doSomething();
}

In this code, it’s easy to tell that count is a variable that may change and MAX_COUNT is a variable that is intended to never change. This convention adds another level of semantics to the underlying code.

The Google JavaScript Style Guide, the SproutCore Style Guide, and the Dojo Style Guide specify that constants should be formatted in this manner (the Dojo Style Guide also allows constants to be specified as Pascal case; see the following section).

Constructors

JavaScript constructors are simply functions that are used to create objects via the new operator. The language contains many built-in constructors, such as Object and RegExp, and developers can add their own constructors to create new types. As with other naming conventions, constructors follow the native language, so constructors are formatted using Pascal case.

Pascal case is the same as camel case except that the initial letter is uppercase. So instead of anotherName, you would use AnotherName. Doing so helps to differentiate constructors from both variables and nonconstructor functions. Constructor names also are typically nouns, as they are used to create instances of a type. Here are some examples:

// Good
function Person(name) {
    this.name = name;
}

Person.prototype.sayName = function() {
    alert(this.name);
};

var me = new Person("Nicholas");

Following this convention also makes it easier to spot errors later. You know that functions whose names are nouns in Pascal case must be preceded by the new operator. Consider the following:

var me = Person("Nicholas");
var you = getPerson("Michael");

Here, line 1 should jump out as a problem to you, but line 2 looks okay according to the conventions already laid out in this chapter.

Crockford’s Code Conventions, the Google JavaScript Style Guide, and the Dojo Style Guide all recommend this practice. JSLint will warn if a constructor is found without an initial uppercase letter or if a constructor function is used without the new operator. JSHint will warn if a constructor is found without an initial uppercase letter only if you add the special newcap option.

Literal Values

JavaScript has several types of primitive literal values: strings, numbers, booleans, null, and undefined. There are also object literals and array literals. Of these, only booleans are self-explanatory in their use. All of the other types require a little bit of thought as to how they should be used for optimum clarity.

Strings

Strings are unique in JavaScript, in that they can be indicated by either double quotes or single quotes. For example:

// Valid JavaScript
var name = "Nicholas says, \"Hi.\"";

// Also valid JavaScript
var name = 'Nicholas says, "Hi"';

Unlike other languages such as Java and PHP, there is absolutely no functional difference between using double quotes and single quotes for strings. They behave exactly the same, except that the string delimiter must be escaped. So in this example, in the string using double quotes, we had to escape the double quote characters, and in the string using single quotes, we did not. What matters is that you pick a single style and stick with it throughout the code base.

Crockford’s Code Conventions and the jQuery Core Style Guide both specify the use of double quotes for strings. The Google JavaScript Style Guide specifies the use of single quotes for strings. I prefer using double quotes, because I tend to switch back and forth between writing Java and JavaScript frequently. Because Java uses only double quotes for strings, I find it easier to switch between contexts by maintaining that convention in JavaScript. This sort of issue should always be a consideration when developing conventions: do what makes it easiest for engineers to do their jobs.

Another aspect of strings is the hidden ability to create multiline strings. This feature was never specified as part of the JavaScript language but still works in all engines:

// Bad
var longString = "Here's the story, of a man \
named Brady.";

Although this is technically invalid JavaScript syntax, it effectively creates a multiline string in code. This technique is generally frowned upon because it relies on a language quirk rather than a language feature, and it is explicitly forbidden in the Google JavaScript Style Guide. Instead of using multiline strings, split the string into multiple strings and concatenate them together:

// Good
var longString = "Here's the story, of a man " +
                 "named Brady.";

Numbers

The number type is unique to JavaScript, because all types of numbers—integers and floats—are stored in the same data type. There are also several literal formats for numbers to represent various numeric formats. Most formats are fine to use, but some are quite problematic:

// Integer
var count = 10;

// Decimal
var price = 10.0;
var price = 10.00;

// Bad Decimal: Hanging decimal point
var price = 10.;

// Bad Decimal: Leading decimal point
var price = .1;

// Bad: Octal (base 8) is deprecated
var num = 010;

// Hexadecimal (base 16)
var num = 0xA2;

// E-notation
var num = 1e23;

The first two problematic formats are the hanging decimal point, such as 10., and the leading decimal point, such as .1. Each format has the same problem: it’s hard to know if the omission of values before or after the decimal point are intentional. It could very well be that the developer mistyped the value. It’s a good idea to always include digits before and after the decimal point to avoid any confusion. These two formats are explicitly forbidden in the Dojo Style Guide. Both JSLint and JSHint warn when one of these two patterns is found.

The last problematic numeric format is the octal format. JavaScript’s support of octal numbers has long been a source of error and confusion. The literal number 010 doesn’t represent 10; it represents 8 in octal. Most developers aren’t familiar with octal format, and there’s rarely a reason to use it, so the best approach is to disallow octal literals in code. Although not called out in any of the popular style guides, both JSLint and JSHint will warn when they come across an octal literal.

Null

The special value null is often misunderstood and confused with undefined. This value should be used in just a few cases:

  • To initialize a variable that may later be assigned an object value

  • To compare against an initialized variable that may or may not have an object value

  • To pass into a function where an object is expected

  • To return from a function where an object is expected

There are also some cases in which null should not be used:

  • Do not use null to test whether an argument was supplied.

  • Do not test an uninitialized variable for the value null.

Here are some examples:

// Good
var person = null;

// Good
function getPerson() {
    if (condition) {
        return new Person("Nicholas");
    } else {
        return null;
    }
}

// Good
var person = getPerson();
if (person !== null) {
    doSomething();
}

// Bad: Testing against uninitialized variable
var person;
if (person != null) {
    doSomething();
}

// Bad: Testing to see whether an argument was passed
function doSomething(arg1, arg2, arg3, arg4) {
    if (arg4 != null) {
        doSomethingElse();
    }
}

The best way to think about null is as a placeholder for an object. These rules are not covered by any major style guide but are important for overall maintainability.

Note

A longer discussion around the pitfalls of null is found in Chapter 8.

Undefined

The special value undefined is frequently confused with null. Part of the confusion is that null == undefined is true. However, these two values have two very different uses. Variables that are not initialized have an initial value of undefined, which essentially means the variable is waiting to have a real value. For example:

// Bad
var person;
console.log(person === undefined);    //true

Despite this working, I recommend avoiding the use of undefined in code. This value is frequently confused with the typeof operator returning the string “undefined” for a value. In fact, the behavior is quite confusing, because typeof will return the string “undefined” both for variables whose value is undefined and for undeclared variables. Example:

// foo is not declared
var person;
console.log(typeof person);     //"undefined"
console.log(typeof foo);        //"undefined"

In this example, both person and foo cause typeof to return “undefined” even though they behave very different in almost every other way (trying to use foo in a statement will cause an error, but using person will not).

By avoiding the use of the special value undefined, you effectively keep the meaning of typeof returning “undefined” to a single case: when a variable hasn’t been declared. If you’re using a variable that may or may not be assigned an object value later on, initialize it to null:

// Good
var person = null;
console.log(person === null);    //true

Setting a variable to null initially indicates your intent for that variable; it should eventually contain an object. The typeof operator returns “object” for a null value, so it can be differentiated from undefined.

Object Literals

Object literals are a popular way to create new objects with a specific set of properties, as opposed to explicitly creating a new instance of Object and then adding properties. For example, this pattern is rarely used:

// Bad
var book = new Object();
book.title = "Maintainable JavaScript";
book.author = "Nicholas C. Zakas";

Object literals allow you to specify all of the properties within two curly braces. Literals effectively perform the same tasks as their nonliteral counterparts, just with more compact syntax.

When defining object literals, it’s typical to include the opening brace on the first line, then each property-value pair on its own line, indented one level, then the closing brace on its own line. For example:

// Good
var book = {
    title: "Maintainable JavaScript",
    author: "Nicholas C. Zakas"
};

This is the format most commonly seen in open source JavaScript code. Though it’s not commonly documented, the Google JavaScript Style Guide does recommend this format. Crockford’s Code Conventions recommends using object literals over the Object constructor but does not specify a particular format.

Array Literals

Array literals, as with object literals, are a more compact way of defining arrays in JavaScript. Explicitly using the Array constructor, as in this example, is generally frowned upon:

// Bad
var colors = new Array("red", "green", "blue");
var numbers = new Array(1, 2, 3, 4);

Instead of using the Array constructor, you can use two square brackets and include the initial members of the array:

// Good
var colors = [ "red", "green", "blue" ];
var numbers = [ 1, 2, 3, 4 ];

This pattern is widely used and quite common in JavaScript. It is also recommended by the Google JavaScript Style Guide and Crockford’s Code Conventions.

Get Maintainable JavaScript now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.