- General
- Naming
- Variable declaration
- Literals
- Semicolons
- Keywords
- Block Statements
- Conditional Statements
- Loops
- Operators
- eval
- undefined
- Parentheses
- Exceptions
- Type Casting
- Multi-Line Statements
- Method Chaining
- String concatenation
- Empty Lines
- Function Context
- Comments
- Classes
- node.js
##General
- 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.
##Naming
variableNamesLikeThisfunctionNamesLikeThisfunctionArgumentsLikeThisClassNamesLikeThismethodNamesLikeThisCONSTANTS_LIKE_THISnamespacesLikeThisevents-like-thisprivateorprotectedproperties and methods should be prefixed with a single_character- Shortened and abbreviated names should be avoided.
- Common abbreviations, such as
JSONandXMLare written inCamelCase. For example:Json,Xml.
##Variable declaration
-
Each variable should be declared:
- using a
varstatement; - 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
varstatement 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();
}##Literals
###Objects
- 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
};###Arrays
- When enumerating elements in an array literal, spaces should be typed after the comma only:
var fellowship = ['foo', 'bar', 'baz'];###Strings
- 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';##Semicolons Statements should always end with a semicolon.
##Keywords
- 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;##Block Statements
- 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; }##Conditional Statements ###if
- The
elsekeyword 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()) {
}###switch 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
}##Loops
###for
If possible, Array.prototype.forEach should be used instead of a for loop.
[1, 2, 3].forEach(function (value) {
console.log(value);
});Performance-critical parts of the code can use a for statement.
###for (var i in obj)
If possible, Object.keys should be used instead of a for-in construction.
Object.keys(obj).forEach(function (key) {
console.log(key);
});##Operators ###'with' operator
The with operator should not be used.
###Comparison Operators
If there is no need for type casting, the strict equality operator === (or strict inequality !==) should be used.
###Ternary Operator 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 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).
##eval
The eval function should be avoided.
json serialized data should be parsed with JSON.parse.
##undefined
Checking for undefined values should be done using the strict equality operator.
Good:
x === undefined;Bad:
typeof x === 'undefined'
x === void 0##Parentheses
- Should be used only if it is required of the expression's syntax or semantics.
- Should not be used with the unary operators
delete,typeofandvoid, or with the keywordsreturn,throwandnew.
##Exceptions
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 Type casting should be done explicitly:
Good:
Boolean(foo)
Number(bar)
String(baz)
[].indexOf(qux) === -1 or [].indexOf(qux) < 0Bad:
!!foo
+bar
baz + ''
~[].indexOf(qux)##Multi-Line Statements
- 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;##Method Chaining 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();##String concatenation
- 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.';##Empty Lines 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);##Function Context
- Binding the context variable for function calls should be done using Function.prototype.bind:
doAsync(function () {
this.fn();
}.bind(this));- Preferably, the context argument 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 current context to a variable, the variable should be named
_this:
var _this = this;
doAsync(function () {
_this.fn();
});##Comments
- 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.
##Classes
- "Symmetrical" methods should be declared one after the other. For example:
var FooClass = inherit({
__constructor: function () {},
// destructors are placed right after the constructor
destruct: function () {},
someMethod: function () {}
});##node.js
###Importing Modules
- 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 hereBad:
var http = require('http');
// code here
var fs = require('fs');
// code hereThis 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.