JavaScript

Frameworks

The following frameworks are preferred, and should be used. The introduction of non-standard frameworks must be discussed with the Front End Technical Authority and the overall Front End Community.

  • jQuery, for cross-browser consistency.
  • Modernizr, for feature detection and cross-browser polyfills.
  • RequireJS, for asynchronous module loading.
  • jQuery plugins for reuse of tried and tested pieces of functionality and other 3rd party plugins. These will be validated for code quality before selection.
  • Picturefill, responsive image polyfill.
  • HTML5Shiv, enable use of HTML5 elements in older browsers.

Do not use any form of browser detection. Use feature/object detection instead, using Modernizr can help with this.


Code formatting

Semicolons

Always use semicolons at the end of each statement, and always place them on the same line as the statement. This ensures your meaning is always interpreted as intended.

var x = 10;
    x = 5;

Quote marks

Using single quote marks to denote string objects.

var link = '<a href="'+ url +'"></a>';

Whitespace

JavaScript code should be formatted to be clean and easy to read. Here are some guidelines on using whitespace to produce well-formatted code.

Use one space before the opening a brace

// Bad
function test(){
    console.log('test');
}

// Good
function test() {
    console.log( 'test' );
}

Use one space before the opening parenthesis in control statements (if, while etc.)

Note: Do not use a space before the argument list in function calls and declarations.

// Bad
if(test) {
    doSomething ();
}

// Good
if ( test ) {
    doSomething();
}

Include one space before and one space after operators

// Bad
var a=b+2;

// Good
var a = b + 2;

Insert one blank line after blocks and before the next statement

// Bad
if ( foo ) {
    return bar;
}
return baz;

// Good
if ( foo ) {
    return bar;
}

return baz;

// Bad
var obj = {
    foo() {
    },
    bar() {
    }
};
return obj;

// Good
var obj = {
    foo() {

    },

    bar() {

    }
};

return obj;

Structure

Files

All JavaScript files should be concatenated and minified for production websites. This means for development and future maintenance JavaScript code should be logically split into small modules, represented by distinct files. The preferred method of modularisation is through the use of CommonJS AMD modules, implemented with RequireJS. The optimiser can concatenate AMD modules as part of a build script. Doing so reduces the total size and HTTP traffic to the browser, which improve overall performance.

Inline scripts

Inline <script> elements should not be present in HTML, except when required by external implementations such as anaytics. In particular, document.write statements must not be present.

Inline scripts block rendering of the page and will increase both actual and perceived load time.

Wrapping lines

Wrap lines after 80 characters, for increased readability in all text editors. If your statement is longer than 80 characters, you should break it. Break it somewhere suitable which will not invite semicolon insertion.

Comments

Single line

// This is a single line comment. There is a space between the token "//" and the comment itself

Where possible place single line comments on the same line as the code they reference, otherwise place them immediately above the code they reference.

Blocks

/**
* this is a comment block, there is an asterisk and a line break after the initial token "/**", an asterisk and
* a space at the beginning of each comment line, and another line break between the end of the comment and the final token "*/"
*/

Place comment blocks immediately above the code they reference.


AMD modules

The preferred way of structuring modern JavaScript websites is through the use of modules that comply with the CommonJS Asynchronous Module Definition (AMD). The most complete implementation is RequireJS which we are using. In this pattern we define modules, and those modules' dependencies as follows:

define( [ 'dependency' ], function( dependency ) {
    return {}; // the module
});

Naming conventions

Constants

JavaScript has no constants. If a value is intended to be constant and immutable, it should be capitalised.

var SPEED_OF_LIGHT = 299792458;

Variables

Use nouns. Variables should be lowercase for short names and camelCase for longer names. Describe what the variable is, not what type of variable it is:

var sum,
    width,
    nameOfUser;

Booleans

The name should convey truthiness if the variable is true, so that conditional statements are made more readable, eg.:

if ( isValid ) {
    ...
}

For booleans relating to plural items consider something line:

if ( isValidList ) {
    ...
}

Function and object naming

Function and Object naming should follow the pattern of variable naming above. Constructor functions and objects which are destined to be inherited from extended subclassed should use Pascal case:

function Circle() {
    ...
}

var Person = {
    name: 'name',
    getName: function() {
        return this.name;
    }
}

Declaration and initialisation of variables

JavaScript variables must be declared in a block at the top of the function, explicitly declaring scope and avoiding hoisting. All variables should be declared with a single var statement followed by a new line. There should be a single space either side of the '=' operator, for readability.

var getTheCurrentMonthName = function() {
    var monthNames = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ],
        theCurrentDate = new Date(),
        theCurrentMonthName = monthNames[ theCurrentDate.getMonth() ];

    return theCurrentMonthName;
}

Comparison operators, equality and truthiness

Use triple-equals to prevent type coercion:

// Bad
if ( myVar == testString ) {
    doSomething();
}

// Bad
if ( myVar != testString ) {
    doSomething();
}

// Good
if ( myVar === testString ) {
    doSomething();
}

// Good
if ( myVar !== testString ) {
    doSomething();
}

Testing for truthiness

Where possible, test for truthiness rather than explicitly comparing a value against null or undefined. For example, here's an if statement:

if ( typeof myVariable !== 'undefined' ) {
    ...
}

This checks the type of myVariable is not equal to the string 'undefined', which is a perfectly valid piece of JavaScript but could be written more clearly and concisely by checking the truthiness of myVariable:

if ( myVariable ) {
    ...
}

This statement checks if myVariable is truthy - that is, if myVariable is declared and has a value that does not evaluate to false. It works in exactly the same way as the first example, but has the advantage of being shorter which saves a few bytes, and additionally removes an immutable string from the codebase. This might sound trivial, but over a large codebase these could add up to kilobytes of code that cannot be compressed by the uglify optimiser.

Beware of testing against an empty string, though - that is a truthy value!

Falsy values

  • false
  • 0 (zero)
  • null
  • undefined
  • NaN

Statements

Variables

var a = 'This line is one statement',
    b = 'This statement is on another line'; // this is a comment directly relating to the variable b

Functions

Functions should be created in one of two ways: a function declaration and a function expression. Both forms of creating a function object are equally valid, you should use each one according to your requirements. It is important to note that function declarations will be parsed first, wherever they appear in your code. Function expressions will be parsed next, in the order they appear in your code. NB. although it is possible to use a named function expressions, this should not be done. It is of limited value, and may create an ambiguity around whether you are using a declaration or an expression.

Function declarations like so:

function getFruit() {
    ...
}

And function expressions like so:

var getFruit = function() {
    ...
}

Objects

When creating an object, use object literal notation rather than instantiating a new object. This slightly reduces the amount of code it is necessary to write, but more importantly makes the code much more readable:

var person = {
    'name': 'Name',
    'age': 50,
    'job': 'Job',
    'skills': [ 'JS', 'HTML5' ]
}

Arrays

Similarly, use array literal notation when creating an array, rather than instantiating a new Array object. This reduces the amount of code required to create the array and is much neater:

var listOfColours = [ 'blue', 'red', 'green' ];

If

Single space after the if, to differentiate from a function declaration. Round brackets surrounding the expression, followed by a single space, curly space, line break, indented code, line break, closing curly brace.

if ( condition ) {
    i = 0;
}

If-else

if ( condition ) {
    i = 0;
} else {
    i = 1;
}

Else block should always appear on the same line as the closing bracket of the if block.

If-else-if

if ( condition ) {
    i = 0;
} else if ( condition ) {
    i = 1;
} else {
    i = 2;
}

Ternary if

This is often used for variable assignment where a variable may be undefined, and a fallback value needs to be assigned if this is the case. For example:

var data = ( myVariable ) ? myVariable : responseData;

However, this practice should be avoided where possible since it can be confusing to read.

Instead, this form of variable assignment can be rewritten like so:

var data = myVariable || responseData;

This uses the logical OR operator to allow the assignment of data to 'fail through' to the value of responseData if myVariable is not defined or is a falsy value such as zero or undefined.

For

Similar to our grammatical conventions elsewhere, use spaces either side of operators, spaces after semicolons and no spaces inside round brackets.

var i,
    len = listOfNames.length;

for ( i = 0; l = len; i++ ) {
    ...
}

Remember to define your iterator and length variables outside of the for statement.

While

var i = 5;
while ( i > 0 ) {
    ...
}

Do...while

This statement should be avoided, because the condition is placed at the of the statement it makes the code block and thus the intent much harder to read. There is always another way to achieve what you want.

Switch

Tab indent once for each condition, and twice for statements following that condition. Always break after each condition. If you need to fall through for any reason, eg. meeting more than one condition, you should use another kind of statement, as your code in a setich statement will be unnecessary confusing.

switch ( myString.length ) {
    case 3:
        alert( '3' );
        break;
    case 4:
        alert( '4' );
        break;
    default:
        alert( 'your string is neither 3 nor 4 characters long' );
}

jQuery

Cache jQuery elements

If you use jQuery to find a DOM node and you need to use that node again further down your JS, assign it to a variable.

var $root = $( '.example' );

Note: the convention for variables that are assigned to jQuery objects is to prefix them with an '$'.

Search using classes and attributes

Search using ID is the fastest lookup, but IDs are mutable and subject to change once the HTML is integrated into a back-end. Instead, use classes, tag names or attributes to find elements.

// Bad
var $element = $( '#element' );

// Good
var $element = $( '.element' );
var $element = $( 'input[type="checkbox"]' );

Note: Avoid using data attributes as search criteria, since these are also subject to change and may not always be present on the element.

Filter your searches

If you are looking for a DOM element in the context of a component, do not search for it across the entire DOM; use jQuery's find() function to restrict your search to the DOM nodes inside that component only.

var $root = $( '.example' ),
    $element;

$element = $root.find( '.element' );

Data storage

Wherever possible it is preferred to use browser based data storage such as ‘session storage’ or ‘local storage’ rather than using cookies.

Legislative requirements

Whenever storing information on user’s equipment it is required that the Privacy and Electronic Communications Regulations are complied with as detailed by the ICO.

Cookies

A cookie’s expiry must not have a lifespan that is longer than is required for its purpose and must not have an expiry of greater than a year. If a cookie is only required for a session that a session cookie must be used.

The size of cookies must be kept as small as possible. Keep values short, for example use 1 or 0 rather than true or false. Do not duplicate data or repeat text where a reference to it could be used instead.