Javascript

Owner: Development Last revision: 12.11.2021

Spacing and Indentation#

Indentation#

Code must be indented with 4 spaces.

// Good
function greet(name) {
    return `Hello ${name}!`;
}

// Bad, only 2 spaces.
function greet(name) {
  return `Hello ${name}!`;
}

Control statements#

When it comes to spaces around symbols or keywords, the rule of thumb is: add them.

// Good
if (true) {
    // ...
} else {
    // ...
}

// Bad, needs more spaces.
if(true){
    // ...
}else{
    // ...
}

Opening braces should always be on the same line as their corresponding statement or declaration (known as the one true brace style).

// Good
if (true) {
    // ...
}

// Bad
if (true)
{
    // ...
}

Infix operators#

Infix operators need room to breath.

// Good
const two = 1 + 1;

// Bad, needs more spaces.
const two = 1+1;

Arrays#

Arrays that contain an object or another array mustn’t have a space between the brackets. Multiline arrays require trailing commas.

// Good
const pairs = ['a', 'b', 'c', 'd'];

// Bad, no extra spaces required
const pairs = [ 'a', 'b', 'c', 'd' ];
// Good
const person = [
    'Adrian',
    'Sebastian',
];

// Bad, no trailing comma.
const person = [
    'Adrian',
    'Sebastian'
];
// Good
const pairs = [['a', 'b'], ['c', 'd']];

// Bad, no extra spaces if the array contains arrays or objects.
const pairs = [ ['a', 'b'], ['c', 'd'] ];

Objects#

Objects require spaces between their braces. Multiline objects require trailing commas.

// Good
const person = { name: 'Sebastian', job: 'Developer' };

// Bad, no spaces between parentheses.
const person = {name: 'Sebastian', job: 'Developer'};
// Good
const person = {
    name: 'Sebastian',
    job: 'Developer',
};

// Bad, no trailing comma.
const person = {
    name: 'Sebastian',
    job: 'Developer'
};
// Good
const people = [{ name: 'Sebastian' }, { name: 'Willem' }];

// Bad, no extra spaces if the array contains arrays or objects.
const people = [ { name: 'Sebastian' }, { name: 'Willem' } ];

Line Length#

Lines shouldn’t be longer than 80 characters, and must not be longer than 120 characters. Comments must not be longer than 80 characters.

Control Structures#

Brackets#

Always use curly brackets.

// Good
if ($condition) {
   ...
}

// Bad
if ($condition) ...

Happy Path#

Generally a function should have its unhappy path first and its happy path last. In most cases this will cause the happy path being in an unindented part of the function which makes it more readable.

// Good

if (!goodCondition) {
    throw new Error;
}

// do work
// Bad

if (goodCondition) {
    // do work
}

throw new Error;

Avoid Else#

In general, else should be avoided because it makes code less readable. In most cases it can be refactored using early returns. This will also cause the happy path to go last, which is desirable.

// Good

if (!conditionA) {
   // conditionA failed
   
   return;
}

if (!conditionB) {
   // conditionA passed, B failed
   
   return;
}

// condition A and B passed

Compound Ifs#

In general, separate if statements should be preferred over a compound condition. This makes debugging code easier.

// Good
if (!conditionA) {
   return;
}

if (!conditionB) {
   return;
}

if (!conditionC) {
   return;
}

// do stuff
// bad
if (conditionA && conditionB && conditionC) {
  // do stuff
}

Quotes#

Use single quotes if possible. If you need multiline strings or interpolation, use template strings.

// Good
import Vue from 'vue';

const company = 'Further';

// Bad, single quotes can be used here.
import Vue from "vue";

const company = "Further";

// Bad, single quotes can be used here.
import Vue from `vue`;

const company = `Further`;
// Good
function greet(name) {
    return `Hello ${name}!`;
}

// Bad, template strings are preferred.
function greet(name) {
    return 'Hello ' + name + '!';
}

Also, when writing html templates (or jsx for that matter), start multiline templates on a new line if possible.

function createLabel(text) {
    return `
        <div class="label">
            ${text}
        </div>
    `;
}

Semicolons#

Always.

Variables#

When assigning variables, prefer const over let. Only use let to indicate that a variable will be reassigned. Never use var.

Assigning#

// Good
const willNotChange = 'a';
let willChange = 'b';

function change(value) {
    willChange = value;
}

// Bad
var willNotChange = 'a';
var willChange = 'b';

function change(value) {
    willChange = value;
}

Naming#

Variable names should always be camelCase.

// Good
const myConstant = 'a';

// Bad
const my_constant = 'a';
const MyOtherConstant = 'a';

Variable names generally shouldn’t be abbreviated.

// Good
function saveUser(user) {
    localStorage.set('user', user);
}

// Bad, it's hard to reason about abbreviations in blocks as they grow.
function saveUser(u) {
    localStorage.set('user', u);
}

In single-line arrow functions, abbreviations are allowed to reduce noise if the context is clear enough. For example, if you’re calling map or forEach on a collection of items, it’s clear that the parameter is an item of a certain type, which can be derived from the collection’s substantive variable name.

// Good
function saveUserSessions(userSessions) {
    userSessions.forEach(s => saveUserSession(s));
}

// Ok, but pretty noisy.
function saveUserSessions(userSessions) {
    userSessions.forEach(userSession => saveUserSession(userSession));
}

Comparisons#

Always use a triple equal to do variable comparisons. If you’re unsure of the type, cast it first.

// Good
const one = 1;
const another = "1";

if (one === parseInt(another)) {
    // ...
}

// Bad
const one = 1;
const another = "1";

if (one == another) {
    // ...
}

Functions#

Naming#

Function names should always be camelCase.

// Good
function myFunction() {
    // ...
}

// Bad
function my_function() {
    // ...
}

function MyOtherFunction() {
    // ...
}

Function keyword vs. arrow functions#

Function declarations should use the function keyword.

// Good
function scrollTo(offset) {
    // ...
}

// Using an arrow function doesn't provide any benefits here, while the
// `function`  keyword immediately makes it clear that this is a function.
const scrollTo = (offset) => {
    // ...
};

Terse, single line functions can also use the arrow syntax. There’s no hard rule here, but make sure it uses the same pattern as surrounding functions.

// Good
function sum(a, b) {
    return a + b;
}

// It's a short and simple method, so squashing it to a one-liner is ok.
const sum = (a, b) => a + b;
// Good
export function query(selector) {
    return document.querySelector(selector);
}

// This one's a bit longer, having everything on one line feels a bit heavy.
// It's not easily scannable unlike the previous example.
export const query = (selector) => document.querySelector(selector);
// Good
function factorial(n) {
    return !(n > 1)
        ? 1
        : factorial(n - 1) * n;
}

function sum(a, b) {
    return a + b;
}

// Bad
function factorial(n) {
    return !(n > 1)
        ? 1
        : factorial(n - 1) * n;
}

const sum = (a, b) => a + b;

Anonymous functions should use arrow functions.

['a', 'b'].map((a) => a.toUpperCase());

Object methods must use the shorthand method syntax.

// Good
export default {
    methods: {
        handleClick(event) {
            event.preventDefault();
        },
    },
};

// Bad, the `function` keyword serves no purpose.
export default {
    methods: {
        handleClick: function (event) {
            event.preventDefault();
        },
    },
};

Arrow Functions Parameter Brackets#

An arrow function’s parameter brackets must not be omitted if the function is a one-liner.

// Good
['a', 'b'].map((a) => a.toUpperCase());

// Bad
['a', 'b'].map(a => a.toUpperCase());

Code Clean-up#

Do not leave commented out CSS code in place.