- General
- Naming
- Variable declaration
- Literals
- Semicolons
- Keywords
- Block statements
- Conditional statements
- Loop statements
- Operators
- eval
- undefined
- Parentheses
- Exceptions
- Type casting
- Multi-line statements
- Method chaining
- String concatenation
- Empty lines
- Comments
- Functions
- Classes
- Enums
- ECMAScript 2015
- ECMAScript 2017
- Node.js
- Licence
- Files should be encoded in UTF-8 without BOM.
- The recommended line-break character is LF -
\n
. - Files should end with a LF character.
- One level of indentation is achieved with 4 space characters.
- Lines should be no longer than 120 characters.
- Trailing whitespace at the end of lines should be removed.
variableNamesLikeThis
functionNamesLikeThis
functionArgumentsLikeThis
ClassNamesLikeThis
EnumNamesLikeThis
methodNamesLikeThis
CONSTANTS_LIKE_THIS
namespacesLikeThis
private
orprotected
properties and methods should be prefixed with a single_
character- Shortened and abbreviated names should be avoided.
- Common abbreviations, such as
JSON
andXML
are written inCamelCase
. For example:Json
,Xml
.
-
Each variable should be declared:
- using a
var
statement; - only once in the current scope;
- on a new line;
- as close as possible to the place where it's first used.
- using a
-
Each
var
statement should have only one variable declared in it.
Good:
var keys = ['foo', 'bar'];
var values = [23, 42];
var object = {};
while (items.length) {
var key = keys.pop();
object[key] = values.pop();
}
Bad:
var keys = ['foo', 'bar'],
values = [23, 42],
object = {},
key;
while (items.length) {
key = keys.pop();
object[key] = values.pop();
}
-
There should be no whitespace after the opening and before the closing curly braces:
var obj = {a: 1, b: 2, c: 3}; this.method({a: 1, b: 2});
-
There should be no whitespace characters before the colon:
var obj = { prop: 0 };
-
Only property names should be aligned within object literals:
Good:
var obj = { a: 0, b: 1, lengthyName: 2 };
Bad:
var obj = { a : 0, b : 1, lengthyName: 2 };
-
Quotes around property names should be typed only if needed:
Good:
var obj = { key: 0, 'key-key': 1 };
Bad:
var obj = { 'key': 0, 'key-key': 1 };
-
Spaces inside computed property brackets should not be used:
Good:
var value = obj[key];
Bad:
var value = obj[ key ];
-
When enumerating elements in an array literal, spaces should be typed after the comma only:
var fellowship = ['foo', 'bar', 'baz'];
-
String literals should use single quotes:
var lyrics = 'Never gonna give you up. Never gonna let you down. Never gonna turn around and desert you.';
-
If a string contains a single quote character, it should be escaped:
var test = 'It shouldn\'t fail';
Statements should always end with a semicolon.
-
Keywords are always followed by a single space character:
if (test) { // ... } function foo() { // ... } var bar = function () { // ... };
-
If the keyword is followed by a semicolon, there should be no space between them:
return;
-
The opening curly brace should be on the same line and separated with one space character:
if (test) { // ... } function foo() { // ... }
-
Branching and looping statements should always be surrounded with curly braces:
Good:
if (test) { return; }
Bad:
if (test) return; if (test) return; if (test) { return; }
-
The
else
keyword should be on the same line as the closing brace of the if-part of the statement:if (test) { // ... } else { // ... }
-
Condition statements should not contain assignment operations:
Good:
var foo = bar(); if (foo > 0) { // ... }
Bad:
var foo; if ((foo = bar()) > 0) { // ... }
-
Logical operators should not be used for conditional branching:
Good:
if (condition) { actionIfTrue(); } else { actionIfFalse(); }
Bad:
condition && actionIfTrue() || actionIfFalse();
-
Conditions longer than the maximum line length should be divided as in the example:
if (longCondition || anotherLongCondition && yetAnotherLongCondition ) { // ... }
-
Yoda conditions should not be used:
Good:
if (getType() === 'driving') { }
Bad:
if ('driving' === getType()) { }
The switch
statement should be written as in the example:
switch (value) {
case 1:
// ...
break;
case 2:
// ...
break;
default:
// ...
// no break keyword on the last case
}
-
Expressions, enclosed in round parentheses, should be separated by space after semicolon:
Good:
for (var i = 0; i < 10; i++) { doSomething(); }
Bad:
for (var i = 0 ; i < 10 ; i++) { doSomething(); }
-
Complicated expressions in round parentheses should be avoided.
-
while
keyword should be on the same line as the closing brace (like in conditional statements):do { statements; } while (condition);
The with
operator should not be used.
If there is no need for type casting, the strict equality operator ===
(or strict inequality !==
) should be used.
The ternary operator should be written as in the examples:
var x = a ? b : c;
var y = a ?
longButSimpleOperandB : longButSimpleOperandC;
var z = a ?
moreComplicatedB :
moreComplicatedC;
Unary operators should be typed without whitespace between them and their operands:
var foo = !bar;
Exceptions from this rule are the unary special JS operators).
The eval
function should be avoided.
json
serialized data should be parsed with JSON.parse.
-
Checking for
undefined
value of declared variable (e.g. function argument) should be done by using the strict equality operator:Explanation:
- In modern browsers (
IE9+
,Opera 12.16+
,Firefox 4+
) undefined is immutable (a non-configurable, non-writable property of the global object). - It prevents undeclared variables usage.
Good:
x === undefined
Bad:
typeof x === 'undefined' x === void 0
Exceptions:
-
typeof
should be used if you need to support old browsers (likeIE8
) wherewindow.undefined
property is mutable. -
typeof
may be used in place wherestring
type is expected:switch (typeof x) { case 'number': // ... case 'undefined': // ... }
- In modern browsers (
-
Checking for existence of a global variable should be done by using
typeof
operator or by checking existence of a property of the global object:Explanation: An attempt to access to undeclared variable will result an error.
if (typeof Foo !== 'undefined') { // ... } // Also okay for browser only code (`window` is unavailable in Node.js) if (window.Foo !== undefined) { // ... }
-
Should not be used with the unary operators
delete
,typeof
andvoid
, or with the keywordsreturn
,throw
andnew
:Good:
delete obj.key; typeof x === 'number'; new Type(); throw new Error();
Bad:
delete(obj.key); typeof(x) === 'number'; new(Type)(); throw(new Error());
-
Explicit parentheses in logical or mathematical expressions can be used to increase readability:
((a - b > c) && c) || (c + d && d + 1) || e; // equivalent to a - b > c && c || c + d && d + 1 || e
throw
should be used with new Error
or an object of a class derived from Error
:
Good:
throw new Error('msg');
Bad:
throw 'msg';
Type casting should be done explicitly:
Good:
Boolean(foo)
Number(bar)
String(baz)
[].indexOf(qux) === -1 or [].indexOf(qux) < 0
Bad:
!!foo
+bar
baz + ''
~[].indexOf(qux)
-
If a statement is longer than the maximum line length, it is split into several lines and properly indented.
-
Lines of the statement should be split after an operator:
var debt = this.calculateBaseDebt() + this.calculateSharedDebt() + this.calculateDebtPayments() + this.calculateDebtFine();
-
Closing parentheses should be on a new line with the indentation of the current block statement:
Good:
DoSomethingThatRequiresALongFunctionName( veryLongArgument1, argument2, argument3, argument4 ); anotherStatement;
Bad:
DoSomethingThatRequiresALongFunctionName( veryLongArgument1, argument2, argument3, argument4); anotherStatement;
When a method is called on a new line, it should:
- Be one indentation level deeper than the target object.
- Begin with the property access operator
.
.
Good:
someObject
.operation()
.operationWithCallback(function (obj) {
obj.processed = true;
})
.end();
Bad:
someObject.
start().
end();
someObject
.start()
.end();
- Strings should be concatenated with the
+
operator. - The
[].join('')
should be avoided. - Escaping newline literals inside strings should be avoided.
Good:
var foo = 'A rather long string of English text, an error message ' +
'actually that just keeps going and going -- an error ' +
'message to make the Energizer bunny blush (right through ' +
'those Schwarzenegger shades)! Where was I? Oh yes, ' +
'you\'ve got an error and all the extraneous whitespace is ' +
'just gravy. Have a nice day.';
Bad:
var foo = 'A rather long string of English text, an error message \
actually that just keeps going and going -- an error \
message to make the Energizer bunny blush (right through \
those Schwarzenegger shades)! Where was I? Oh yes, \
you\'ve got an error and all the extraneous whitespace is \
just gravy. Have a nice day.';
A single empty line can be used as a separator for grouping the code into logical blocks:
doSomethingTo(x);
doSomethingElseTo(x);
andThen(x);
nowDoSomethingWith(y);
andNowWith(z);
- In-line comments should start with
//
. Between the//
and the text of the comment should be one space character. - Comments for functions, classes, etc. should be written according to the jsdoc documentation syntax.
-
Binding the
this
value for function calls should be done using Function.prototype.bind:doAsync(function () { this.fn(); }.bind(this));
Note: in ECMAScript 6 arrow functions are preferred.
-
Preferably, the argument for
this
value should be used (if available):Good:
[1, 2, 3].forEach(function (n) { this.fn(n); }, this);
Bad:
[1, 2, 3].forEach(function (n) { this.fn(n); }.bind(this));
-
If assigning the
this
value to a variable, the variable should be named_this
:var _this = this; doAsync(function () { _this.fn(); });
Assignment in return statement should be avoided:
Good:
var lazyCompute = (function () {
var result;
return function () {
if (!result) {
result = compute();
}
return result;
}
}());
Bad:
var lazyCompute = (function () {
var result;
return function () {
return result || (result = compute());
}
}());
-
"Symmetrical" methods should be declared one after the other. For example:
function Foo() {} // Destructors are placed right after the constructor. Foo.prototype.destruct = function () {}; Foo.prototype.someMethod = function () {};
-
Constructor should not be used as a factory function:
Explanation:
- It makes code explicit.
- It simplifies migration to ES6 classes, because class constructors cannot be
invoked without
new
.
Bad:
function Foo(bar) { if (!(this instanceof Foo)) { return new Foo(bar); } // ... } var foo = Foo();
- Enum names should be in
UpperCamelCase
. - Enum members should be in
ALL_CAPS
.
var Color = {
BLUE: '#0000dd',
RED: '#dd0000'
};
This section describes code style for ECMAScript 2015 Language Specification.
-
Strict mode should be used.
Explanation:
- It prevents nasty bugs.
- Many useful features of language (e.g. classes, let declaration, block scopes) are available only in strict mode.
- It simplifies migration to ES6 modules, because they are executed in strict mode.
-
Strict mode should be enabled explicity using the
'use strict'
pragma.Explanation:
- Dependencies of your code may not work in strict mode.
- Your code can be used in non-strict mode.
-
Avoid using
var
. -
All immutable references should be declared using a const.
-
let should be used only for mutable references (i.e. when variable will be (re)assigned different value later in the code).
Good:
const count = observers.length; let index = 0; while (index < count) { const observer = observers[index]; observer(...args); index = index + 1; }
Bad:
// Reader expects count to change! let count = observers.length; let index = 0; while (index < count) { const observer = observers[index]; observer(...args); index = index + 1; } const count = observers.length; let index = 0; while (index < count) { // Reader expects observer to change within the block! let observer = observers[index]; observer(...args); index = index + 1; } const count = observers.length; // Do not use `var` var index = 0; while (index < count) { observers[index](...args); index = index + 1; }
-
If the reference is immutable, but the value is mutable,
const
decalaration should be used:Good:
const query = {}; query.param = 'value';
Bad:
let query = {}; query.param = 'value';
-
For class definition the
class
keyword should be used:Good:
class Circle { constructor(x, y, radius) { this.x = x; this.y = y; this.radius = radius; } area() { return Math.PI * this.radius * this.radius; } }
Bad:
function Circle(x, y, radius) { this.x = x; this.y = y; this.radius = radius; } Circle.prototype.area = function () { return Math.PI * this.radius * this.radius; };
-
There should be one whitespace after the class name:
Good:
class Circle {}
Bad:
class Circle{}
-
There should be no whitespace after method name:
Good:
class Circle { area() {} }
Bad:
class Circle { area () {} }
-
There should be one whitespace before the opening curly brace of method's body:
Bad:
class Circle { area(){} }
-
The constructor (if exists) should be the first method in a class definition:
Good:
class Circle { constructor() {} area() {} }
Bad:
class Circle { area() {} constructor() {} }
-
For inheritance the
extends
keyword should be used:Good:
class Stream extends EventEmitter {}
Bad:
var util = require('util'); class Stream() { constructor() { EventEmitter.call(this); } } util.inherits(Stream, EventEmitter);
-
Arrow function should be used where an anonymous function is expected (when you need function and you don't want bind it to an identifier):
Explanation: Arrow functions capture the
this
value of the enclosing context. That prevents run-time errors with unexpected values ofthis
. Also it's a more efficient method than bindingthis
value usingFunction.prototype.bind
.[1, 2, 3].map((x) => { // ... }); // Use `function` here, because pass `someObj` as `this` argument. [1, 2, 3].map(function (x) { // ... }, someObj); // Use `function` here, because specify name. decorate(function createSomething() { // ... });
-
Always add parentheses around arrow function parameters:
Explanation:
- This style is consistent with cases when function takes zero or more than one parameters.
- You need to alter the code less, if the number of parameters changes.
Good:
[1, 2, 3].map((x) => x * 2); [1, 2, 3].reduce((acc, n) => acc + n);
Bad:
[1, 2, 3].map(x => x * 2);
-
Before and after an arrow function's arrow (
=>
) whitespace is required:[1, 2, 3].map((x) => x * 2);
-
If the function body consists of a single expression, braces should be omitted:
Good:
[1, 2, 3].map((x) => x * 2);
Bad:
[1, 2, 3].map((x) => { return x * 2; });
-
Spaces in placeholders (after
${
and before}
) should not be used:Good:
`Hello ${name}`
Bad:
`Hello ${ name }`
-
Spaces around the
=
sign should be used:Good:
function project(point, zoom = 23) {}
Bad:
function project(point, zoom=23) {}
-
In destructuring assignment rules for Objects and Arrays should be used:
Good:
const [a, b] = someArray; const {a, b} = someObject;
Bad:
const [ a, b ] = someArray; const { a, b } = someObject;
-
If some value in
array destructuring
is ignored, it should not be marked with space:Good:
const [first,, third] = ['foo', 'bar', 'baz']; const [,, third] = ['foo', 'bar', 'baz'];
Bad:
const [first, , third] = ['foo', 'bar', 'baz']; const [ , , third] = ['foo', 'bar', 'baz'];
-
For default values spaces around
=
should be used:Good:
function sendRequest({cache = true, timeout = 200}) {}
Bad:
function sendRequest({cache=true, timeout=200}) {}
-
Long destructuring patterns should be written as in the example:
const { protocol, hostname, port, pathname, query } = url.parse(urlString); function formatUrl({ protocol, hostname, port, pathname, query }) { // ... }
-
Rest parameters should be preferred instead arguments object.
-
Spread operator should be preferred instead Function.prototype.apply.
-
The space between
rest
orspread
operator and their expressions should not be used:Good:
let [head, ...tail] = someArray; function foo(...args) {}
Bad:
let [head, ... tail] = someArray; function foo(... args) {}
-
The asterisk
*
in a generator declaration should be sticked to thefunction
keyword:Good:
function* createIterator() { yield 1; } const createIterator = function* () { yield 1; };
Bad:
function *createIterator() { yield 1; } const createIterator = function * () { yield 1; };
-
In a shorthand method the asterisk should be sticked to the
method name
:Good:
class Graph { *edges() {} }
Bad:
class Graph { * edges() {} }
-
In an yield* expression the asterisk should be sticked to the
yield
keyword:Good:
function* gen() { yield* anotherGen(); }
Bad:
function* gen() { yield *anotherGen(); }
-
There should be no whitespace after the opening and before the closing curly braces (like in objects):
Good:
import {name1, name2} from 'foo';
Bad:
import { name1, name2 } from 'foo';
-
Long named imports and exports should be written as in the examples:
import { name1 as localName1, name2, name3, name4 } from 'src/foo'; export { name1 as exportName1, name2, name3, name4 };
-
Avoid unnecessary
return await
.Explanation: An async function always wraps the return value in a
Promise
. Usingreturn await
just adds extra time before the resulting promise is resolved without changing the semantics.Good:
async function foo() { return bar(); }
Bad:
async function foo() { return await bar(); }
-
Don't use
async
when it has no useful effect.It's easy to get in the habit of using async on any function that does anything related to asynchrony. But in some cases, it's extraneous. If you can omit the async without changing the behavior of the function, do so.
Good:
function afterTwoThings(first, second) { return Promise.all([first, second]); }
Bad:
async function afterTwoThings(first, second) { return Promise.all([first, second]); }
Cases where async is useful include:
- You are using await. (This is the obvious one.)
- You are returning an error asynchronously.
- You are returning a value and you want it implicitly wrapped in a promise.
Good:
async function asyncError() { throw new Error('Error!'); } const asyncValue = async () => 'value';
-
Modules should be imported in the beginning of the file, after the description of the module (if present):
Good:
var http = require('http'); var fs = require('fs'); // code here
Bad:
var http = require('http'); // code here var fs = require('fs'); // code here
Exception: This rule does not apply to modules that are imported "on demand".
-
Module import calls should be grouped according to the following order:
- Standard node.js modules (i.e. fs, util, etc.).
- External lib modules.
- Modules of the current application.