This is a normative guide on how to format JavaScript. The main aim is to get the best possible readability. It is especially optimized for ECMAScript 2015, but should work equally good with other versions.
It's assumed that the code will be optimized by code minifiers and/or package tools for usage in a production client-side environment.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
var
keywordelse
The easiest way to adhere to this guide is to use the included eslint-config-javascript module to check your files. In order to set it up, fist install ESLint and the module:
npm install --save-dev eslint eslint-config-javascript
Next add a eslint.config.js
file to your root directory
with the following content:
import eslintConfJs from "eslint-config-javascript"
export default [
...eslintConfJs,
]
This will load the configuration of this styleguide.
Finally add a lint
script to the package scripts:
"scripts": {
"lint": "eslint --max-warnings=0 --ignore-pattern=.gitignore .",
…
}
Now you can check your files for conformity simply by running
npm run lint
_this
MUST be used as a reference to this
Reasoning:
Originally this guide required the use of tabs for indentation. The problem, however, is that a tab character can have any length (normally 2 or 4 characters wide). This undermines the purpose of monospaced fonts, where every character is supposed to have the same length to ensures alignment and predictability of the text layout.
Semicolons MUST NOT be used to terminate statements
except the next line starts with an (
, [
or `
An inline comma MUST be followed by one space character
const colors = ["green", "yellow", "red"]
instead of
const colors = ["green","yellow","red"]
Trailing commas MUST be used in Arrays
const fruits = [
apple,
banana,
melon,
]
instead of
const fruits = [
apple,
banana,
melon
]
… and Objects
const person = {
firstName: "John",
lastName: "Smith",
}
instead of
const person = {
firstName: "John",
lastName: "Smith"
}
Reasoning:
To add an element to the end of an Array or Object, 2 lines must be modified. This adds unnecessary visual clutter to diffs. Furthermore, elements can be more easily rearranged when they all have the same structure.
No leading commas MUST be used
const fruits = [
apple,
banana,
peach,
melon,
]
instead of
const fruits = [ apple
, banana
, peach
, melon
]
and
const person = {
firstName: "John",
lastName: "Smith",
age: 30,
}
instead of
const person = { firstName: "John"
, lastName: "Smith"
, age: 30
}
Read only references to a value MUST be declared with const
const answerToEverything = 42
instead of
let answerToEverything = 42
Reassignable variables must be declared with let
let currentPage = 138
function turnPageOver () {
currentPage += 1
}
instead of
const currentPage = 138
function turnPageOver () {
currentPage += 1
}
var
keywordVariables must never be declared with var
Each variable MUST be declared with exactly one const
or let
keyword
const name = "John"
const age = 34
const instrument = "guitar"
instead of
const name = "John",
age = 34,
instrument = "guitar"
If a variable shall be exposed globally
it MUST be explicitly declared as a property
of the global scope (window
/global
object)
window.brandName = "Stark Industries"
// or
global.brandName = "Stark Industries"
instead of
brandName = "Stark Industries"
Unassigned let
variables MUST be declared last in a group of declarations
const foo = 7
let bar = 4
let baz
Line breaks must occur after operators:
const sentence = "This is a " +
"short sentence."
Except for the ternary operator:
const status = isTesting
? "We are currently testing"
: "Everything operational"
Placing the ?
and the :
at the beginning of the line
makes it easier to skim the code.
===
MUST be used instead of ==
!==
MUST be used instead of !=
except in value != null
where it has the same effect as value !== null && value !== undefined
Shortcuts MAY be used where appropriate:
if (name) {
…
}
instead of
if (name !== "") {
…
}
and
if (collection.length) {
…
}
instead of
if (collection.length > 0) {
…
}
Blocks MAY be used to create an encapsulated scope
{
const age = 34
}
{
const age = 27
}
Before and after the condition must be a single space character.
if (testValue) {
doSomething()
}
instead of
if(testValue){
doSomething()
}
Blocks MAY be omitted in single line statements but must be used for multiline statements.
if (testValue) doSomething()
// or
if (testValue) {
doSomething()
}
if (testValue) {
doSomething()
doThisToo()
}
else
else
MUST be placed on a newline after the if
-block.
if (testValue) {
doSomething()
}
else if (otherTestValue) {
doSomethingElse()
}
else {
doDefault()
}
instead of
if (testValue) {
doSomething()
} else if (otherTestValue) {
doSomethingElse()
} else {
doDefault()
}
Reasoning:
if
and else
blockelse
is at the beginning of the line it's easier to skim down
a list of if
s and else
s.Obscure code SHOULD be commented but not obvious things So do not write comments like this:
// If person is older than 34
if (person.age > 34) {
…
}
//
MUST be used for single line comments//
and the first character of the comment// FIXME:
MAY be used to annotate problems// TODO:
MAY be used to capture issues which need to get solved/* … */
MUST be used for multiline comments/*
This is a
multiline comment
*/
Double quotes MUST be used for strings.
Since most languages use double quotes for strings, this reduces the friction in multi-language projects.
Anonymous functions MUST start with a !
!function () {
…
}
Reasoning:
(function () {})
can lead to errors
when relying on ASI (Automatic Semicolon Insertion)
or when concatenating several JavaScript files
Indentation SHOULD be used for long method chains. At the most one method should be called per line.
$("#items")
.find(".selected")
.highlight()
instead of
$("#items").find(".selected").highlight()
Methods SHOULD return this
to enable method chaining.
Properties SHOULD be settable via setters and via a set*
method
to enable chaining.
person.status = single
person
.setName("John")
.marryTo("Linda")
.setStatus("married")
This enables easy traversing of structures involving several classes:
database
.load("John")
.setAge("34")
.sister
.husband
.setName("Tom")
Retrieving of properties MUST at least be implemented via a getter.
console.log(person.age)
instead of
console.log(person.age())
String(123)
Number("123")
Boolean(1)
To array:
Array.from("test")
// => ["t", "e", "s", "t"]
function doSomething () {
Array.from(arguments)
}
doSomething(1, 2, 3)
// => [1, 2, 3]
// TODO: to date, …
You MAY (when it's absolutely necessary) differ from any rules of this guide to increase performance. You MUST, however, explain the reasons for not sticking to a rule in a comment.
Object variables MUST be prefixed with a $
const $form = $("#myForm")
instead of
const form = $("#myForm")
Lookups MUST be cached
const $form = $("#form")
$form.css({
"background-color": "pink"
})
// …
$form.hide()
instead of
$("#form").css({
"background-color": "pink"
})
// …
$("#form").hide()
Imports and requires should be sorted by type.
To improve readability keep an empty newline between each section and 2 empty newlines below all imports / requires.
For example ES2015 style imports:
import path from "path"
import fs from "fs"
import lodash from "lodash"
import app from "./source/app"
const port = 1234
The same applies to CommonJS requires:
const path = require("path")
const fs = require("fs")
const lodash = require("lodash")
const app = require("./source/app")
const port = 1234
Every non-primitive function should look like this:
function doSomething (options = {}) {
const {
hasThis = true, // Some clear description why this is here
isThat = false, // More clear descriptions
importantNumber = 1234, // The clearest description in the universe
content = "Some thoughtful text", // Crystal clear
} = options
// Optional type checks
if (typeof importantNumber !== "number") {
throw new TypeError(
`importantNumber must be a number and not "${importantNumber}"`
)
}
}
This ensures: