Code Guide

Standards for developing flexible, durable, and sustainable HTML, CSS, and JavaScript.

Table of contents

JavaScript (ES5 and below)

JavaScript (ES5 and below)

JavaScript files

<!DOCTYPE html>
<html lang="en-us">
  <head><link rel="stylesheet" media="all" href="styles/application.css">
  </head>
  <body><!-- Place your JS includes at the bottom of the body -->
    <script src="scripts/application.js"></script>
  </body>
</html>

Syntax

// Module and class names should be upper-camel-case
window.MyModule = {  };

// Function and variable names should be lower-camel-case
function myFunction(parameter1) {
    // Indent four spaces
    for (var i = 0; i < list.length; i++) {
        console.log(list[i]);
    }

    // Break really long lines at 100 characters, after an operator or comma
    var aReallyLongVariableName = aLudicrouslyLongFunctionName(parameterOne, parameterTwo,
            {
                optionOne: "a",
                optionTwo: "blah"
            });
}

Whitespace

Blank lines improve readability by setting off sections of code that are logically related.

Blank spaces should be used in the following circumstances:

/*
** Bad
**
** Incomprehensible gobbledygook.
*/
var results=myFunction(parameter1,parameter2),
    obj={property1:[]};
for(var i=0;i<results.length;i++){
    // …
}
var anotherObj={one:"a",two:"b",three:"c"};

/*
** Good
**
** Sooo much better.
*/
// No space between function name and ( for function invocations
// Space around operators and after every comma
var results = myFunction(parameter1, parameter2),
              // Spaces inside {}
    obj     = { property1: [] };

// Space between for and (, and between ) and {
// Space after ; in for
// No space around unary operators like ++ unless it's a word, like typeof
for (var i = 0; i < results.length; i++) {
    // No spaces around . () or []
    obj.property1.append(results[i]);
}

// Space following : in object declarations
var anotherObj = {
    one: "a",
    two: "b",
    three: "c"
};

Comments

Be generous with comments. It is useful to leave information that will be read at a later time by people (possibly yourself) who will need to understand what you have done. The comments should be well-written and clear, just like the code they are annotating. An occasional nugget of humor might be appreciated. Frustrations and resentments will not.

It is important that comments be kept up-to-date. Erroneous comments can make programs even harder to read and understand.

Make comments meaningful. Focus on what is not immediately visible. Don't waste the reader's time with the obvious.

Generally use line comments. Save block comments for formal documentation.

// Don't do this, Captain Obvious.
i = 0; // Set i to zero.

Variable declarations

All variables should be declared before used. JavaScript does not require this, but doing so makes the program easier to read and makes it easier to detect undeclared variables that may become implied globals. Implied global variables should never be used. Use of global variables should be minimized.

The var statement should be the first statement in the function body.

It is preferred that each variable be given its own line, and comment if necessary—though there is no substitute for using a meaningful name. Value clarity over brevity in variable names. They should be listed in alphabetical order if possible.

JavaScript does not have block scope, so defining variables in blocks can confuse programmers who are experienced with other C family languages. Define all variables at the top of the function.

// Not so good
var currentEntry, level, size;

// Good: name your variables meaningfully
var currentTableEntry,
    indentationLevel,  // Only add a comment if necessary
    tableSize;

Function declarations

All functions should be declared before they are used. Inner functions should follow the var statement. This helps make it clear what variables are included in its scope.

There should be no space between the name of a function and the ( (left parenthesis) of its parameter list. There should be one space between the ) (right parenthesis) and the { (left curly brace) that begins the statement body. The body itself is indented four spaces. The } (right curly brace) is aligned with the line containing the beginning of the declaration of the function.

This convention works well with JavaScript because in JavaScript, functions and object literals can be placed anywhere that an expression is allowed. It provides the best readability with inline functions and complex structures.

If a function literal is anonymous, there should be one space between the word function and the ( (left parenthesis). If the space is omitted, then it can appear that the function's name is function, which is an incorrect reading.

Use of global functions should be minimized.

When a function is to be invoked immediately, the entire invocation expression should be wrapped in parens so that it is clear that the value being produced is the result of the function and not the function itself.

// No space between function name and parameter list
// in function declarations
function outer(c, d) {
    var e = c * d;

    // Inner functions should come after var
    function inner(a, b) {
        return (e * a) + b;
    }

    return inner(0, 1);
}

// It's not too hard to make complex code readable if you follow the rules
function getElementsByClassName(className) {
    var results = [];
    walkTheDOM(document.body, function (node) {
        var array,                // array of class names
            ncn = node.className; // the node's classname

        // If the node has a class name, then split it into a list of simple names.
        // If any of them match the requested name, then append the node to the list of results.

        if (ncn && ncn.split(' ').indexOf(className) >= 0) {
            results.push(node);
        }
    });
    return results;
}

// Space between function keyword and ( for anonymous functions
div.onclick = function (e) {
    return false;
};

that = {
    method: function () {
        return this.datum;
    },
    datum: 0
};

// IIFE: immediately-invoked function expression
var collection = (function () {
    var keys = [], values = [];

    return {
        get: function (key) {
            var at = keys.indexOf(key);
            if (at >= 0) {
                return values[at];
            }
        },
        set: function (key, value) {
            var at = keys.indexOf(key);
            if (at < 0) {
                at = keys.length;
            }
            keys[at] = key;
            values[at] = value;
        },
        remove: function (key) {
            var at = keys.indexOf(key);
            if (at >= 0) {
                keys.splice(at, 1);
                values.splice(at, 1);
            }
        }
    };
}());

Names

Names should be formed from the 26 upper and lower case letters (A .. Z, a .. z), and the 10 digits (0 .. 9). Avoid use of international characters because they may not read well or be understood everywhere. Though it is legal syntax, do not use _ (underbar) in names, instead preferring to put function and variable names in lowerCamelCase. Do not use \ (backslash) in names. Only use $ (dollar sign) in variable names if you are denoting that the variable contains a jQuery object.

Do not use _ (underbar) as the first or last character of a name. It is sometimes intended to indicate privacy, but it does not actually provide privacy. If privacy is important, use the forms that provide private members. Avoid conventions that demonstrate a lack of competence.

Most variables and functions should start with a lower case letter.

Constructor functions that must be used with the new prefix should start with a capital letter. JavaScript issues neither a compile-time warning nor a run-time warning if a required new is omitted. Bad things can happen if new is not used, so the capitalization convention is the only defense we have.

Global variables should be in all caps. JavaScript does not have macros or constants, but also use all caps for variables you'd make constant if you could.

ECMAScript 6 (ES6/ES2015) introduces the const keyword, which gets close to the desired behavior of disallowing reassignment or redeclaration, but doesn't cause compile-time errors on reassignment and isn't yet supported across modern browsers.

// Bad
function _notReallyPrivate() {
    // …
}

function my_function(parameter) {
    // …
}

// Good
function myFunction(parameter) {
    // …
}

// Capitalize functions intended to be constructors used with new
function Vehicle() {
    // …
}

var vehicle = new Vehicle();

/*
** Use the $ prefix to indicate that the variable contains
** a jQuery object
*/
var $listItems = $('.list-item');

/*
** Use all caps for global variables and things you wish
** were constant
*/
var PST_OFFSET = -8;

Statements

Simple statements

Each line should contain at most one statement. Put a ; (semicolon) at the end of every simple statement. Note that an assignment statement that is assigning a function literal or object literal is still an assignment statement and must end with a semicolon.

JavaScript allows any expression to be used as a statement. This can mask some errors, particularly in the presence of semicolon insertion. The only expressions that should be used as statements are assignments and invocations.

Compound statements

Compound statements are statements that contain lists of statements enclosed in { } (curly braces).

Labels

Statement labels are optional. Only these statements should be labeled: while, do, for, switch.

return statement

A return statement with a value should not use ( ) (parentheses) around the value. The return value expression must start on the same line as the return keyword in order to avoid semicolon insertion.

if statement

The if class of statements should have the form shown to the right.

The ternary operator ?

Ternary operators are fine to use as long as what's happening in the code is clear. Keep the statement simple and never nest them. A rule of thumb here is that if your ternary statement is long enough to wrap on to multiple lines, it’s too long. In that case, simply using if is easier to read and understand.

for statement

The for class of statements should have the forms shown to the right.

The first form should be used with arrays and with loops of a predeterminable number of iterations.

The second form should be used with objects. Be aware that members that are added to the prototype of the object will be included in the enumeration. It is wise to program defensively by using the hasOwnProperty method to distinguish the true members of the object.

while statement

A while statement should have the form shown to the right.

do statement

A do statement should have the form shown to the right.

Unlike the other compound statements, the do statement always ends with a ; (semicolon).

switch statement

A switch statement should have the form shown to the right.

Each case is aligned with the switch. This avoids over-indentation. A case label is not a statement, and should not be indented like one.

Each group of statements (except the default) should end with break, return, or throw. Do not fall through.

try statement

A try statement should have the form shown to the right.

continue statement

Avoid use of the continue statement. It tends to obscure the control flow of the function.

with statement

The with statement should not be used:

// ----- [ compound statements ] -----------------
// Bad
if (condition)
{
    // statements
}

// Good
if (condition) {
    // statements
}

// Okay when if spans multiple lines, to make
// clear where block begins
if (condition1 ||
    condition2 ||
    condition3)
{
    // statements
}


// ----- [ if statements ] -----------------------
// Bad
if (condition) return false;

// Worse
if (condition)
    return false;

// Good: always use braces, even around single statements
if (condition) {
    // statements
}

if (condition) {
    // statements
} else {
    // statements
}

if (condition) {
    // statements
} else if (condition) {
    // statements
} else {
    // statements
}

// ----- [ ternary operator ] --------------------
// Bad
var firstCheck = false,
    secondCheck = false,
    access = firstCheck ? "Access denied" : secondCheck ? "Access denied" : "Access granted";

// You will go to hell for this. What does it even mean?
var age = 16;

var url = age > 18 ? (
    alert("OK, you can go."),
    "continue.html"
) : (
    alert("You are much too young!"),
    alert("Sorry :-("),
    "stop.html"
);

location.assign(url);

// Good. Obvious and understandable.
var fee = isMember ? "$2.00" : "$10.00";

// ----- [ for statements ] ----------------------
// type 1
for (initialization; condition; update) {
    // statements
}

// type 2
for (variable in object) {
    if (filter) {
        // statements
    }
}

// Use hasOwnProperty when using for-in loops
for (variable in object) {
    if (object.hasOwnProperty(variable)) {
        // statements
    }
}

// ----- [ while statements ] --------------------
while (condition) {
    // statements
}

// ----- [ do statements ] -----------------------
do {
    // statements
} while (condition);

// ----- [ switch statements ] -------------------
switch (expression) {
case expression:
    // statements
default:
    // statements
}

// ----- [ try statements ] ----------------------
try {
    // statements
} catch (variable) {
    // statements
}

try {
    // statements
} catch (variable) {
    // statements
} finally {
    // statements
}

Other conventions

Use strict mode

Always use strict mode. It disables such undesirable features as implicit global variable declaration and in general makes your code behave more predictably.

Named function expressions

Always use named function expressions:

{} and []

Use {} instead of new Object(). Use [] instead of new Array().

Use arrays when the member names would be sequential integers. Use objects when the member names are arbitrary strings or names.

, (comma) Operator

Avoid the use of the comma operator. (This does not apply to the comma separator, which is used in object literals, array literals, var statements, and parameter lists.)

Block scope

In JavaScript blocks do not have scope. Only functions have scope. Do not use blocks except as required by the compound statements.

ES2015 introduces the let keyword, which along with const is block scoped. Even so, as stated above, avoid creating blocks around let, and only use blocks as required by compound statements.

Assignment expressions

Avoid doing assignments in the condition part of if and while statements.

Is assignment or comparison intended? Avoid constructs that cannot easily be determined to be correct.

=== and !== operators

Use the === and !== operators. The == and != operators do type coercion and should not be used.

Confusing pluses and minuses

Be careful to not follow a + with + or ++. This pattern can be confusing. Insert parens between them to make your intention clear.

eval is evil

The eval function is the most misused feature of JavaScript. Avoid it. Similar to the with statement:

eval has aliases. Do not use the Function constructor. Do not pass strings to setTimeout or setInterval.

"use strict"; // Enable strict mode for the entire file

// ----- [ named function expressions ] ----------
var foo = function bar() {
    // bar is accessible inside the function's scope, and
    // will show up in the stack trace. What's not to love?
    // …
}


// ----- [ assignment expressions ] --------------
// By this
if (a = b) {
    // statements
}

// Did you mean this instead?
if (a == b) {
    // statements
}


// ----- [ pluses and minuses ] ------------------
// Bad
// + + could be misread as ++
total = subtotal + +myInput.value;

// Better
total = subtotal + (+myInput.value);

Asynchronous patterns

Error-first callbacks

When writing Node.js code, take care to define your callbacks in the idiomatic error-first style:

Learn more about error-first callbacks in Node.js.

Managing complicated asynchronous code

When orchestrating several asynchronous operations, consider using a promises library like Q or abstraction library like async instead of nesting callbacks inside callbacks inside callbacks etc. They'll make complex asynchronous code easier to read and untangle.

Read more about promises.

// ----- [ error-first callbacks ] ---------------
fs.readFile('/foo.txt', function (err, data) {
    // If an error occurred, handle it (throw, propagate, etc)
    if(err) {
        console.log('Unknown Error');
        return;
    }
    // Otherwise, log the file contents
    console.log(data);
});