Open rogerxu opened 8 years ago
const
for all of your references; avoid using var
.
prefer-const
, no-const-assign
let
instead of var
.
no-var
let
and const
are block-scoped.3.1 Use the literal syntax for object creation.
no-new-object
3.2 Use computed property names when creating objects with dynamic property names.
3.3 Use object method shorthand.
object-shorthand
3.4 Use property value shorthand.
object-shorthand
3.5 Group your shorthand properties at the beginning of your object declaration.
3.6 Only quote properties that are invalid identifiers.
quote-props: "as-needed"
3.7 Do not call Object.property
methods directly.
no-prototype-builtins
// bad
console.log(object.hasOwnProperty(key));
// best
const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
/* or */
import has from 'has';
// …
console.log(has.call(object, key));
3.8 Prefer the object spread operator over Object.assign
to shallow-copy objects. Use the object rest operator to get a new object with certain properties omitted.
// very bad
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ
delete copy.a; // so does this
// bad
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
// good
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
4.1 Use the literal syntax for array creation.
no-array-constructor
4.2 Use Array.prototype.push
instead of direct assignment to add items to an array.
4.3 Use array spreads ...
to copy arrays.
const itemsCopy = [...items];
4.4 To convert an iterable object to an array, use spreads ...
instead of Array.from
.
// good
const nodes = Array.from(foo);
// best
const nodes = [...foo];
4.5 Use Array.from
for converting an array-like object to an array.
// bad
const arr = Array.prototype.slice.call(arrLike);
// good
const arr = Array.from(arrLike);
4.6 Use Array.from
instead of spread ...
for mapping over iterables, because it avoids creating an intermediate array.
// bad
const baz = [...foo].map(bar);
// good
const baz = Array.from(foo, bar);
4.7 Use return statements in array method callbacks. It’s ok to omit the return if the function body consists of a single statement returning an expression without side effects.
array-callback-return
4.8 Use line breaks after open and before close array brackets if an array has multiple lines.
// bad
const arr = [
[0, 1], [2, 3], [4, 5],
];
const objectInArray = [{
id: 1,
}, {
id: 2,
}];
const numberInArray = [
1, 2,
];
// good
const arr = [[0, 1], [2, 3], [4, 5]];
const objectInArray = [
{
id: 1,
},
{
id: 2,
},
];
const numberInArray = [
1,
2,
];
5.1 Use object destructuring when accessing and using multiple properties of an object.
prefer-destructuring
function getFullName({ firstName, lastName }) {
return `${firstName} ${lastName}`;
}
5.2 Use array destructuring.
prefer-destructuring
const [first, second] = arr;
5.3 Use object destructuring for multiple return values, not array destructuring.
function processInput(input) {
// then a miracle occurs
return { left, right, top, bottom };
}
// the caller selects only the data they need
const { left, top } = processInput(input);
''
for strings.
quotes
prefer-template
, template-curly-spacing
eval()
on a string, it opens too many vulnerabilities.
no-eval
no-useless-escape
7.1 Use named function expressions instead of function declarations.
func-style
: "expression", {"allowArrowFunctions": true}
// bad
function foo() {
// ...
}
// bad
const foo = function () {
// ...
};
// good
// lexical name distinguished from the variable-referenced invocation(s)
const short = function longUniqueMoreDescriptiveLexicalFoo() {
// ...
};
7.2 Wrap immediately invoked function expressions in parentheses.
wrap-iife
// immediately-invoked function expression (IIFE)
(function () {
console.log('Welcome to the Internet. Please follow me.');
}());
7.3 Never declare a function in a non-function block (if
, while
, etc). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears.
no-llop-func
7.4 ECMA-262 defines a block
as a list of statements. A function declaration is not a statement.
// bad
if (currentUser) {
function test() {
console.log('Nope.');
}
}
// good
let test;
if (currentUser) {
test = () => {
console.log('Yup.');
};
}
7.5 Never name a parameter arguments
. This will take precedence over the arguments
object that is given to every function scope.
// bad
function foo(name, options, arguments) {
// ...
}
// good
function foo(name, options, args) {
// ...
}
7.6 Never use arguments
, opt to use rest syntax ...
instead.
prefer-rest-params
// bad
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join('');
}
// good
function concatenateAll(...args) {
return args.join('');
}
7.7 Use default parameter syntax rather than mutating function arguments.
function handleThings(opt = {}) {
// ...
}
7.8 Avoid side effects with default parameters.
7.9 Always put default parameters last.
function handleThings(name, opt = {}) {
// ...
}
7.10 Never use the Function constructor to create a new function.
no-new-func
7.11 Spacing in a function signature.
space-before-function-paren
, space-before-blocks
// bad
const f = function(){};
const g = function (){};
const h = function() {};
// good
const x = function () {};
const y = function a() {};
7.12 Never mutate parameters.
no-param-reassign: {"props": false}
// bad
function f1(obj) {
obj.key = 1;
}
// good
function f2(obj) {
const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
}
7.13 Never reassign parameters.
no-param-reassign
function f1(a) {
a = 1;
// ...
}
function f2(a) {
if (!a) { a = 1; }
// ...
}
// good
function f3(a) {
const b = a || 1;
// ...
}
function f4(a = 1) {
// ...
}
7.14 Prefer the use of the spread operator ...
to call variadic functions.
prefer-spread
// bad
const x = [1, 2, 3, 4, 5];
console.log.apply(console, x);
// good
const x = [1, 2, 3, 4, 5];
console.log(...x);
// bad
new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));
// good
new Date(...[2016, 8, 5]);
7.15 Functions with multiline signatures, or invocations, should be indented just like every other multiline list in this guide: with each item on a line by itself, with a trailing comma on the last item.
function-paren-newline
// bad
function foo(bar,
baz,
quux) {
// ...
}
// good
function foo(
bar,
baz,
quux,
) {
// ...
}
// bad
console.log(foo,
bar,
baz);
// good
console.log(
foo,
bar,
baz,
);
8.1 When you must use an anonymous function (as when passing an inline callback), use arrow function notation.
prefer-arrow-callback
, arrow-spacing
// bad
[1, 2, 3].map(function (x) {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
8.2 If the function body consists of a single statement returning an expression without side effects, omit the braces and use the implicit return. Otherwise, keep the braces and use a return
statement.
arrow-parens
, arrow-body-style
// bad
[1, 2, 3].map(number => {
const nextNumber = number + 1;
`A string containing the ${nextNumber}.`;
});
// good
[1, 2, 3].map(number => `A string containing the ${number}.`);
// good
[1, 2, 3].map((number) => {
const nextNumber = number + 1;
return `A string containing the ${nextNumber}.`;
});
8.3 In case the expression spans over multiple lines, wrap it in parentheses for better readability.
// bad
['get', 'post', 'put'].map(httpMethod => Object.prototype.hasOwnProperty.call(
httpMagicObjectWithAVeryLongName,
httpMethod
)
);
// good
['get', 'post', 'put'].map(httpMethod => (
Object.prototype.hasOwnProperty.call(
httpMagicObjectWithAVeryLongName,
httpMethod
)
));
8.4 If your function takes a single argument and doesn’t use braces, omit the parentheses. Otherwise, always include parentheses around arguments for clarity and consistency.
arrow-parens: ["as-needed", {"requireForBlockBody": true}]
// bad
[1, 2, 3].map((x) => x * x);
// good
[1, 2, 3].map(x => x * x);
// good
[1, 2, 3].map(number => (
`A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
));
// bad
[1, 2, 3].map(x => {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
8.5 Avoid confusing arrow function syntax (=>
) with comparison operators (<=
, >=
).
no-confusing-arrow
// bad
const itemHeight = item => item.height > 256 ? item.largeSize : item.smallSize;
// bad
const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize;
// good
const itemHeight = item => (item.height > 256 ? item.largeSize : item.smallSize);
// good
const itemHeight = (item) => {
const { height, largeSize, smallSize } = item;
return height > 256 ? largeSize : smallSize;
};
8.6 Enforce the location of arrow function bodies with implicit returns.
implicit-arrow-linebreak
// bad
(foo) =>
bar;
(foo) =>
(bar);
// good
(foo) => bar;
(foo) => (bar);
(foo) => (
bar
)
9.1 Always use class
. Avoid manipulating prototype
directly.
// bad
function Queue(contents = []) {
this.queue = [...contents];
}
Queue.prototype.pop = function () {
const value = this.queue[0];
this.queue.splice(0, 1);
return value;
};
// good
class Queue {
constructor(contents = []) {
this.queue = [...contents];
}
pop() {
const value = this.queue[0];
this.queue.splice(0, 1);
return value;
}
}
9.2 Use extends
for inheritance.
// bad
const inherits = require('inherits');
function PeekableQueue(contents) {
Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function () {
return this.queue[0];
};
// good
class PeekableQueue extends Queue {
peek() {
return this.queue[0];
}
}
9.3 Methods can return this
to help with method chaining.
// good
class Jedi {
jump() {
this.jumping = true;
return this;
}
setHeight(height) {
this.height = height;
return this;
}
}
const luke = new Jedi();
luke.jump()
.setHeight(20);
9.4 It's okay to write a custom toString()
method, just make sure it works successfully and causes no side effects.
9.5 Classes have a default constructor if one is not specified. An empty constructor function or one that just delegates to a parent class is unnecessary.
no-useless-constructor
// bad
class Jedi {
constructor() {}
getName() {
return this.name;
}
}
// bad
class Rey extends Jedi {
constructor(...args) {
super(...args);
}
}
// good
class Rey extends Jedi {
constructor(...args) {
super(...args);
this.name = 'Rey';
}
}
9.6 Avoid duplicate class members.
no-dupe-class-members
// bad
class Foo {
bar() { return 1; }
bar() { return 2; }
}
// good
class Foo {
bar() { return 1; }
}
// good
class Foo {
bar() { return 2; }
}
10.1 Always use modules (import
/ export
) over a non-standard module system. You can always transpile to your preferred module system.
// bad
const AirbnbStyleGuide = require('./AirbnbStyleGuide');
module.exports = AirbnbStyleGuide.es6;
// ok
import AirbnbStyleGuide from './AirbnbStyleGuide';
export default AirbnbStyleGuide.es6;
// best
import { es6 } from './AirbnbStyleGuide';
export default es6;
10.2 Do not use wildcard imports.
// bad
import * as AirbnbStyleGuide from './AirbnbStyleGuide';
// good
import AirbnbStyleGuide from './AirbnbStyleGuide';
10.3 Do not export directly from an import.
// bad
// filename es6.js
export { es6 as default } from './AirbnbStyleGuide';
// good
// filename es6.js
import { es6 } from './AirbnbStyleGuide';
export default es6;
10.4 Only import from a path in one place.
no-duplicate-imports
// bad
import foo from 'foo';
// … some other imports … //
import { named1, named2 } from 'foo';
// good
import foo, { named1, named2 } from 'foo';
// good
import foo, {
named1,
named2,
} from 'foo';
10.5 Do not export mutable bindings.
import/no-mutable-exports
// bad
let foo = 3;
export { foo };
// good
const foo = 3;
export { foo };
10.6 In modules with a single export, prefer default export over named export.
import/prefer-default-export
// bad
export function foo() {}
// good
export default function foo() {}
10.7 Put all imports
above non-import statements.
import/imports-first
// bad
import foo from 'foo';
foo.init();
import bar from 'bar';
// good
import foo from 'foo';
import bar from 'bar';
foo.init();
10.8 Multiline imports should be indented just like multiline array and object literals.
// bad
import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';
// good
import {
longNameA,
longNameB,
longNameC,
longNameD,
longNameE,
} from 'path';
10.9 Disallow Webpack loader syntax in module import statements.
import/no-webpack-loader-syntax
// bad
import fooSass from 'css!sass!foo.scss';
import barCss from 'style!css!bar.css';
// good
import fooSass from 'foo.scss';
import barCss from 'bar.css';
for-in
or for-of
.
no-iterator
, no-restricted-syntax
11.3 If you must use generators, make sure their function signature is spaced properly.
generator-star-spacing
// bad
function * foo() {
// ...
}
// bad const bar = function * () { // ... };
// bad const baz = function *() { // ... };
// bad const quux = function*() { // ... };
// bad function*foo() { // ... }
// bad function *foo() { // ... }
// very bad function * foo() { // ... }
// very bad const wat = function * () { // ... };
// good function* foo() { // ... }
// good const foo = function* () { // ... };
dot-notation
[]
when accessing properties with a variable.12.3 Use exponentiation operator **
when calculating exponentiations.
no-restricted-properties
// bad
const binary = Math.pow(2, 10);
// good
const binary = 2 ** 10;
13.1 Always use const
or let
to declare variables. Not doing so will result in global variables. We want to avoid polluting the global namespace.
no-undef
, prefer-const
13.2 Use one const
or let
declaration per variable or assignment.
one-var: "never"
13.3 Group all const
and then group all let
.
13.4 Assign variables where you need them, but place them in a reasonable place
13.5 Do not chain variable assignments.
no-multi-assign
13.6 Avoid using unary increments and decrements (++
, --
).
no-plusplus
13.7 Avoid linebreaks before or after =
in an assignment. If your assignment violates max-len
, surround the value in parens.
operator-linebreak
// bad
const foo =
superLongLongLongLongLongLongLongLongFunctionName();
// bad
const foo
= 'superLongLongLongLongLongLongLongLongString';
// good
const foo = (
superLongLongLongLongLongLongLongLongFunctionName()
);
// good
const foo = 'superLongLongLongLongLongLongLongLongString';
13.8 Disallow unused variables.
no-unused-vars
14.1 typeof
is no longer safe.
14.2 Anonymous function expressions hoist their variable name, but not the function assignment.
function example() {
console.log(anonymous); // => undefined
anonymous(); // => TypeError anonymous is not a function
var anonymous = function () {
console.log('anonymous function expression');
};
}
14.3 Named function expressions hoist the variable name, not the function name or the function body.
function example() {
console.log(named); // => undefined
named(); // => TypeError named is not a function
superPower(); // => ReferenceError superPower is not defined
var named = function superPower() {
console.log('Flying');
};
}
// the same is true when the function name
// is the same as the variable name.
function example() {
console.log(named); // => undefined
named(); // => TypeError named is not a function
var named = function named() {
console.log('named');
};
}
14.4 Function declarations hoist their name and the function body.
function example() {
superPower(); // => Flying
function superPower() {
console.log('Flying');
}
}
15.1 Use ===
and !==
over ==
and !=
.
eqeqeq
15.2 Conditional statements such as the if
statement evaluate their expression using coercion with the ToBoolean
abstract method.
if ([0] && []) {
// true
// an array (even an empty one) is an object, objects will evaluate to true
}
15.3, 15.4 Use shortcuts for booleans, but explicit comparisons for strings and numbers.
// bad
if (name) {
// ...
}
// good
if (name !== '') {
// ...
}
// bad
if (collection.length) {
// ...
}
// good
if (collection.length > 0) {
// ...
}
15.5 Use braces to create blocks in case
and default
clauses that contain lexical declarations (e.g. let
, const
, function
, and class
).
no-case-declarations
15.6 Ternaries should not be nested and generally be single line expressions.
no-nested-ternary
// bad
const foo = maybe1 > maybe2
? "bar"
: value1 > value2 ? "baz" : null;
// split into 2 separated ternary expressions
const maybeNull = value1 > value2 ? 'baz' : null;
// better
const foo = maybe1 > maybe2
? 'bar'
: maybeNull;
// best
const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
15.7 Avoid unneeded ternary statements.
no-unneeded-ternary
// bad
const foo = a ? a : b;
const bar = c ? true : false;
const baz = c ? false : true;
// good
const foo = a || b;
const bar = !!c;
const baz = !c;
15.8 When mixing operators, enclose them in parentheses. The only exception is the standard arithmetic operators (+
, -
, *
, & /
) since their precedence is broadly understood.
no-mixed-operators
// bad
const foo = a && b < 0 || c > 0 || d + 1 === 0;
// bad
const bar = a ** b - 5 % d;
// bad
// one may be confused into thinking (a || b) && c
if (a || b && c) {
return d;
}
// good
const foo = (a && b < 0) || c > 0 || (d + 1 === 0);
// good
const bar = (a ** b) - (5 % d);
// good
if (a || (b && c)) {
return d;
}
// good
const bar = a + b / c * d;
16.1 Use braces with all multi-line blocks.
nonblock-statement-body-position
// bad
if (test)
return false;
// good
if (test) return false;
// good
if (test) {
return false;
}
// bad
function foo() { return false; }
// good
function bar() {
return false;
}
16.2 If you’re using multi-line blocks with if
and else
, put else
on the same line as your if
block’s closing brace.
brace-style: "1tbs"
// bad
if (test) {
thing1();
thing2();
}
else {
thing3();
}
// good
if (test) {
thing1();
thing2();
} else {
thing3();
}
16.3 If an if
block always executes a return
statement, the subsequent else
block is unnecessary. A return
in an else if
block following an if
block that contains a return
can be separated into multiple if
blocks.
no-else-return
// bad
function foo() {
if (x) {
return x;
} else {
return y;
}
}
// bad
function cats() {
if (x) {
return x;
} else if (y) {
return y;
}
}
// bad
function dogs() {
if (x) {
return x;
} else {
if (y) {
return y;
}
}
}
// good
function foo() {
if (x) {
return x;
}
return y;
}
// good
function cats() {
if (x) {
return x;
}
if (y) {
return y;
}
}
// good
function dogs(x) {
if (x) {
if (z) {
return y;
}
} else {
return z;
}
}
17.1 In case your control statement (if
, while
etc.) gets too long or exceeds the maximum line length, each (grouped) condition could be put into a new line. The logical operator should begin the line.
// good
if (
foo === 123
&& bar === 'abc'
) {
thing1();
}
// good
if (
(foo === 123 || bar === 'abc')
&& doesItLookGoodWhenItBecomesThatLong()
&& isThisReallyHappening()
) {
thing1();
}
// good
if (foo === 123 && bar === 'abc') {
thing1();
}
17.2 Don't use selection operators in place of control statements.
// bad
!isRunning && startRunning();
// good
if (!isRunning) {
startRunning();
}
18.1 Use /** ... */
for multi-line comments.
18.2 Use //
for single line comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment unless it's on the first line of a block.
line-comment-position
: {"position": "above"}lines-around-comment
:18.3 Start all comments with a space to make it easier to read.
spaced-comment
// bad
//is current tab
const active = true;
// good
// is current tab
const active = true;
// bad
/**
*make() returns a new element
*based on the passed-in tag name
*/
function make(tag) {
// ...
return element;
}
// good
/**
* make() returns a new element
* based on the passed-in tag name
*/
function make(tag) {
// ...
return element;
}
18.4 Prefixing your comments with FIXME
or TODO
helps other developers quickly understand if you’re pointing out a problem that needs to be revisited, or if you’re suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable.
18.5 Use // FIXME:
to annotate problems.
18.6 Use // TODO:
to annotate solutions to problems.
19.1 Use soft tabs set to 2 spaces.
indent
: 219.2 Place 1 space before the leading brace.
space-before-blocks
: "always"// bad
function test(){
console.log('test');
}
// good
function test() {
console.log('test');
}
19.3
keyword-spacing
: {"before": true, "after": true}// bad
if(isJedi) {
fight ();
}
// good
if (isJedi) {
fight();
}
space-before-function-paren
// bad
function fight () {
console.log ('Swooosh!');
}
// good
function fight() {
console.log('Swooosh!');
}
19.4 Set off operators with spaces.
space-infix-ops
19.5 End files with a single newline character.
eol-last
19.6 Use indentation when making long method chains (more than 2 method chains). Use a leading dot.
newline-per-chained-call
: {"ignoreChainWithDepth": 2}no-whitespace-before-property
// bad
$('#items').find('.selected').highlight().end().find('.open').updateCount();
// bad
$('#items').
find('.selected').
highlight().
end().
find('.open').
updateCount();
// good
$('#items')
.find('.selected')
.highlight()
.end()
.find('.open')
.updateCount();
// bad
const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
.attr('width', (radius + margin) * 2).append('svg:g')
.attr('transform', `translate(${radius + margin},${radius + margin})`)
.call(tron.led);
// good
const leds = stage.selectAll('.led')
.data(data)
.enter().append('svg:svg')
.classed('led', true)
.attr('width', (radius + margin) * 2)
.append('svg:g')
.attr('transform', `translate(${radius + margin},${radius + margin})`)
.call(tron.led);
// good
const leds = stage.selectAll('.led').data(data);
19.7 Leave a blank line after blocks and before the next statement.
// bad
const obj = {
foo() {
},
bar() {
},
};
return obj;
// good
const obj = {
foo() {
},
bar() {
},
};
return obj;
19.8 Do not pad your blocks with blank lines.
padded-blocks
: "never"19.9 Do not add spaces inside parentheses.
space-in-parens
: "never"// bad
function bar( foo ) {
return foo;
}
// good
function bar(foo) {
return foo;
}
// bad
if ( foo ) {
console.log(foo);
}
// good
if (foo) {
console.log(foo);
}
19.10 Do not add spaces inside brackets.
array-bracket-spacing
: "never"// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);
// good
const foo = [1, 2, 3];
console.log(foo[0]);
19.11 Add spaces inside curly braces.
object-curly-spacing
: "always"// bad
const foo = {clark: 'kent'};
// good
const foo = { clark: 'kent' };
19.12 Avoid having lines of code that are longer than 100 characters (including whitespace). Note: per above, long strings are exempt from this rule, and should not be broken up.
max-len
: 10019.13 Require consistent spacing inside an open block token and the next token on the same line. This rule also enforces consistent spacing inside a close block token and previous token on the same line.
block-spacing
// bad
function foo() {return true;}
if (foo) { bar = 0;}
// good
function foo() { return true; }
if (foo) { bar = 0; }
19.14 Avoid spaces before commas and require a space after commas.
comma-spacing
// bad
var foo = 1,bar = 2;
var arr = [1 , 2];
// good
var foo = 1, bar = 2;
var arr = [1, 2];
19.15 Enforce spacing inside of computed properties.
computed-property-spacing
// bad
obj[foo ]
obj[ 'foo']
var x = {[ b ]: a}
obj[foo[ bar ]]
// good
obj[foo]
obj['foo']
var x = { [b]: a }
obj[foo[bar]]
19.16 Enforce spacing between functions and their invocations.
func-call-spacing
// bad
func ();
func
();
// good
func();
19.17 Enforce spacing between keys and values in object literal properties.
key-spacing
// bad
var obj = { "foo" : 42 };
var obj2 = { "foo":42 };
// good
var obj = { "foo": 42 };
19.18 Avoid trailing spaces at the end of lines.
no-trailing-spaces
19.19 Avoid multiple empty lines and only allow one newline at the end of files.
no-multiple-empty-lines
comma-style
: "last"comma-dangle
: "only-multiline"semi
: "always"22.1 Perform type coercion at the beginning of the statement.
22.2 Strings
no-new-wrappers
// => this.reviewScore = 9;
// bad
const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf()
// bad
const totalScore = this.reviewScore.toString(); // isn't guaranteed to return a string
// good
const totalScore = String(this.reviewScore);
22.3 Numbers: Use Number
for type casting and parseInt
always with a radix for parsing strings.
radix
no-new-wrappers
const inputValue = '4';
// bad
const val = new Number(inputValue);
// bad
const val = +inputValue;
// bad
const val = inputValue >> 0;
// bad
const val = parseInt(inputValue);
// good
const val = Number(inputValue);
// good
const val = parseInt(inputValue, 10);
22.4 If for whatever reason you are doing something wild and parseInt
is your bottleneck and need to use Bitshift for performance reasons, leave a comment explaining why and what you're doing.
// good
/**
* parseInt was the reason my code was slow.
* Bitshifting the String to coerce it to a
* Number made it a lot faster.
*/
const val = inputValue >> 0;
22.5 Note: Be careful when using bitshift operations. Numbers are represented as 64-bit values, but bitshift operations always return a 32-bit integer (source). Bitshift can lead to unexpected behavior for integer values larger than 32 bits. Discussion. Largest signed 32-bit Int is 2,147,483,647:
2147483647 >> 0 //=> 2147483647
2147483648 >> 0 //=> -2147483648
2147483649 >> 0 //=> -2147483647
22.6 Booleans:
no-new-wrappers
const age = 0;
// good
const hasAge = Boolean(age);
// best
const hasAge = !!age;
23.1 Avoid single letter names. Be descriptive with your naming.
id-length
: {"min": 2}23.2 Use camelCase when naming objects, functions, and instances.
camelcase
23.3 Use PascalCase only when naming constructors or classes.
new-cap
23.4 Do not use trailing or leading underscores.
no-underscore-dangle
23.5 Do not save references to this
. Use arrow functions or Function#bind
23.6 A base filename should exactly match the name of its default export.
// good
import CheckBox from './CheckBox'; // PascalCase export/import/filename
import fortyTwo from './fortyTwo'; // camelCase export/import/filename
import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index"
// ^ supports both insideDirectory.js and insideDirectory/index.js
23.7 Use camelCase when you export-default a function. Your filename should be identical to your function's name.
function makeStyleGuide() {
// ...
}
export default makeStyleGuide;
23.8 Use PascalCase when you export a constructor / class / singleton / function library / bare object.
const AirbnbStyleGuide = {
es6: {
}
};
export default AirbnbStyleGuide;
23.9 Acronyms and initialisms should always be all capitalized, or all lowercased.
// bad
import SmsContainer from './containers/SmsContainer';
// bad
const HttpRequests = [
// ...
];
// good
import SMSContainer from './containers/SMSContainer';
// good
const HTTPRequests = [
// ...
];
// also good
const httpRequests = [
// ...
];
// best
import TextMessageContainer from './containers/TextMessageContainer';
// best
const requests = [
// ...
];
23.10 You may optionally uppercase a constant only if it (1) is exported, (2) is a const (it can not be reassigned), and (3) the programmer can trust it (and its nested properties) to never change.
const
variables? - This is unnecessary, so uppercasing should not be used for constants within a file. It should be used for exported constants however.EXPORTED_OBJECT.key
) and maintain that all nested properties do not change.// bad
const PRIVATE_VARIABLE = 'should not be unnecessarily uppercased within a file';
// bad
export const THING_TO_BE_CHANGED = 'should obviously not be uppercased';
// bad
export let REASSIGNABLE_VARIABLE = 'do not use let with uppercase variables';
// ---
// allowed but does not supply semantic value
export const apiKey = 'SOMEKEY';
// better in most cases
export const API_KEY = 'SOMEKEY';
// ---
// bad - unnecessarily uppercases key while adding no semantic value
export const MAPPING = {
KEY: 'value'
};
// good
export const MAPPING = {
key: 'value'
};
24.1 Accessor functions for properties are not required.
24.2 Do not use JavaScript getters/setters as they cause unexpected side effects and are harder to test, maintain, and reason about. Instead, if you do make accessor functions, use getVal()
and setVal('hello')
.
// bad
class Dragon {
get age() {
// ...
}
set age(value) {
// ...
}
}
// good
class Dragon {
getAge() {
// ...
}
setAge(value) {
// ...
}
}
24.3 If the property is a boolean, use isVal()
or hasVal()
.
// bad
if (!dragon.age()) {
return false;
}
// good
if (!dragon.hasAge()) {
return false;
}
24.4 It is okay to create get()
and set()
functions, but be consistent.
class Jedi {
constructor(options = {}) {
const lightsaber = options.lightsaber || 'blue';
this.set('lightsaber', lightsaber);
}
set(key, val) {
this[key] = val;
}
get(key) {
return this[key];
}
}
25.1 When attaching data payloads to events, pass an object literal (also known as a "hash") instead of a raw value. This allows a subsequent contributor to add more data to the event payload without finding and updating every handler for the event.
// bad
$(this).trigger('listingUpdated', listing.id);
// ...
$(this).on('listingUpdated', (e, listingID) => {
// do something with listingID
});
// good
$(this).trigger('listingUpdated', { listingID: listing.id });
// ...
$(this).on('listingUpdated', (e, data) => {
// do something with data.listingID
});
$
.$('.sidebar ul')
or parent > child $('.sidebar > ul')
.find
with scoped jQuery object queries.29.1 Use Number.isNaN
instead of global isNaN
.
no-restricted-globals
// bad
isNaN('1.2'); // false
isNaN('1.2.3'); // true
// good
Number.isNaN('1.2.3'); // false
Number.isNaN(Number('1.2.3')); // true
29.2 Use Number.isFinite
instead of global isFinite
.
no-restricted-globals
// bad
isFinite('2e3'); // true
// good
Number.isFinite('2e3'); // false
Number.isFinite(parseInt('2e3', 10)); // true
HTML5 provides us with lots of semantic elements aimed to describe precisely the content. Make sure you benefit from its rich vocabulary.
Make sure you understand the semantics of the elements you're using. It's worse to use a semantic element in a wrong way than staying neutral.
<!-- bad -->
<h1>
<figure>
<img alt=Company src=logo.png>
</figure>
</h1>
<!-- good -->
<h1>
<img alt=Company src=logo.png>
</h1>
Keep your code terse. Forget about your old XHTML habits.
<!-- bad -->
<!doctype html>
<html lang=en>
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf-8" />
<title>Contact</title>
<link rel=stylesheet href=style.css type=text/css />
</head>
<body>
<h1>Contact me</h1>
<label>
Email address:
<input type=email placeholder=you@email.com required=required />
</label>
<script src=main.js type=text/javascript></script>
</body>
</html>
<!-- good -->
<!doctype html>
<html lang=en>
<meta charset=utf-8>
<title>Contact</title>
<link rel=stylesheet href=style.css>
<h1>Contact me</h1>
<label>
Email address:
<input type=email placeholder=you@email.com required>
</label>
<script src=main.js></script>
</html>
Accessibility shouldn't be an afterthought. You don't have to be a WCAG expert to improve your website, you can start immediately by fixing the little things that make a huge difference, such as:
alt
attribute properly<div class=button>
atrocities)<!-- bad -->
<h1><img alt=Logo src=logo.png></h1>
<!-- good -->
<h1><img alt=Company src=logo.png></h1>
While defining the language and character encoding is optional, it's recommended to always declare both at document level, even if they're specified in your HTTP headers. Favor UTF-8 over any other character encoding.
<!-- bad -->
<!doctype html>
<title>Hello, world.</title>
<!-- good -->
<!doctype html>
<html lang=en>
<meta charset=utf-8>
<title>Hello, world.</title>
</html>
Unless there's a valid reason for loading your scripts before your content, don't block the rendering of your page.
If your style sheet is heavy, isolate the styles that are absolutely required initially and defer the loading of the secondary declarations in a separate style sheet. Two HTTP requests is significantly slower than one, but the perception of speed is the most important factor.
<!-- bad -->
<!doctype html>
<meta charset=utf-8>
<script src=analytics.js></script>
<title>Hello, world.</title>
<p>...</p>
<!-- good -->
<!doctype html>
<meta charset=utf-8>
<title>Hello, world.</title>
<p>...</p>
<script src=analytics.js></script>
While the semicolon is technically a separator in CSS, always treat it as a terminator.
/* bad */
div {
color: red
}
/* good */
div {
color: red;
}
The box model should ideally be the same for the entire document. A global * { box-sizing: border-box; }
is fine, but don't change the default box model on specific elements if you can avoid it.
/* bad */
div {
width: 100%;
padding: 10px;
box-sizing: border-box;
}
/* good */
div {
padding: 10px;
}
Don't change the default behavior of an element if you can avoid it. Keep elements in the natural document flow as much as you can. For example, removing the white-space below an image shouldn't make you change its default display:
/* bad */
img {
display: block;
}
/* good */
img {
vertical-align: middle;
}
Similarly, don't take an element off the flow if you can avoid it.
/* bad */
div {
width: 100px;
position: absolute;
right: 0;
}
/* good */
div {
width: 100px;
margin-left: auto;
}
There are many ways to position elements in CSS. Favor modern layout specifications such as Flexbox and Grid, and avoid removing elements from the normal document flow, for example with position: absolute
.
Minimize selectors tightly coupled to the DOM. Consider adding a class to the elements you want to match when your selector exceeds 3 structural pseudo-classes, descendant or sibling combinators.
/* bad */
div:first-of-type :last-child > p ~ *
/* good */
div:first-of-type .info
Avoid overloading your selectors when you don't need to.
/* bad */
img[src$=svg], ul > li:first-child {
opacity: 0;
}
/* good */
[src$=svg], ul > :first-child {
opacity: 0;
}
Don't make values and selectors hard to override. Minimize the use of id
's and avoid !important
.
/* bad */
.bar {
color: green !important;
}
.foo {
color: red;
}
/* good */
.foo.bar {
color: green;
}
.foo {
color: red;
}
Overriding styles makes selectors and debugging harder. Avoid it when possible.
/* bad */
li {
visibility: hidden;
}
li:first-child {
visibility: visible;
}
/* good */
li + li {
visibility: hidden;
}
Don't duplicate style declarations that can be inherited.
/* bad */
div h1, div p {
text-shadow: 0 1px 0 #fff;
}
/* good */
div {
text-shadow: 0 1px 0 #fff;
}
Keep your code terse. Use shorthand properties and avoid using multiple properties when it's not needed.
/* bad */
div {
transition: all 1s;
top: 50%;
margin-top: -10px;
padding-top: 5px;
padding-right: 10px;
padding-bottom: 20px;
padding-left: 10px;
}
/* good */
div {
transition: 1s;
top: calc(50% - 10px);
padding: 5px 10px 20px;
}
Prefer English over math.
/* bad */
:nth-child(2n + 1) {
transform: rotate(360deg);
}
/* good */
:nth-child(odd) {
transform: rotate(1turn);
}
Kill obsolete vendor prefixes aggressively. If you need to use them, insert them before the standard property.
/* bad */
div {
transform: scale(2);
-webkit-transform: scale(2);
-moz-transform: scale(2);
-ms-transform: scale(2);
transition: 1s;
-webkit-transition: 1s;
-moz-transition: 1s;
-ms-transition: 1s;
}
/* good */
div {
-webkit-transform: scale(2);
transform: scale(2);
transition: 1s;
}
Favor transitions over animations. Avoid animating other properties than opacity
and transform
.
/* bad */
div:hover {
animation: move 1s forwards;
}
@keyframes move {
100% {
margin-left: 100px;
}
}
/* good */
div:hover {
transition: 1s;
transform: translateX(100px);
}
Use unitless values when you can. Favor rem
if you use relative units. Prefer seconds over milliseconds.
/* bad */
div {
margin: 0px;
font-size: .9em;
line-height: 22px;
transition: 500ms;
}
/* good */
div {
margin: 0;
font-size: .9rem;
line-height: 1.5;
transition: .5s;
}
If you need transparency, use rgba
. Otherwise, always use the hexadecimal format.
/* bad */
div {
color: hsl(103, 54%, 43%);
}
/* good */
div {
color: #5a3;
}
Avoid HTTP requests when the resources are easily replicable with CSS.
/* bad */
div::before {
content: url(white-circle.svg);
}
/* good */
div::before {
content: "";
display: block;
width: 20px;
height: 20px;
border-radius: 50%;
background: #fff;
}
Don't use them.
/* bad */
div {
// position: relative;
transform: translateZ(0);
}
/* good */
div {
/* position: relative; */
will-change: transform;
}
File names must be all lowercase and may include underscores (_
) or dashes (-
), but no additional punctuation. Follow the convention that your project uses. Filenames’ extension must be .js
.
For any character that has a special escape sequence (\'
, \"
, \\
, \b
, \f
, \n
, \r
, \t
, \v
), that sequence is used rather than the corresponding numeric escape (e.g \x0a
, \u000a
, or \u{a}
). Legacy octal escapes are never used.
For the remaining non-ASCII characters, either the actual Unicode character (e.g. ∞
) or the equivalent hex or Unicode escape (e.g. \u221e
) is used, depending only on which makes the code easier to read and understand.
// Best: perfectly clear even without a comment.
const units = 'μs';
// Allowed, but there’s no reason to do this.
const units = '\u03bcs'; // 'μs'
// Allowed, but awkward and prone to mistakes.
const units = '\u03bcs'; // Greek letter mu, 's'.
// Poor: the reader has no idea what this is.
const units = '\u03bcs';
// Good: use escapes for non-printable characters, and comment if necessary.
return '\ufeff' + content; // byte order mark
A source file consists of, in order:
@fileoverview
JSDoc, if presentgoog.module
statementgoog.require
statementsExactly one blank line separates each section that is present, except the file's implementation, which may be preceded by 1 or 2 blank lines.
@fileoverview
JSDoc, if presentSee 7.5
goog.module
statementAll files must declare exactly one goog.module
name on a single line: lines containing a goog.module
declaration must not be wrapped, and are therefore an exception to the 80-column limit.
goog.module('search.urlHistory.UrlHistoryService');
Module namespaces may never be named as a direct child of another module's namespace.
// bad
goog.module('foo.bar'); // 'foo.bar.qux' would be fine, though
goog.module('foo.bar.baz');
goog.setTestOnly
The single goog.module
statement may optionally be followed by a call to goog.setTestOnly()
.
goog.module.declareLegacyNamespace
Do not use ES6 modules yet (i.e. the export
and import
keywords), as their semantics are not yet finalized. Note that this policy will be revisited once the semantics are fully-standard.
goog.require
statementsgoog.require
.goog.require
statements may not appear anywhere else in the file.// bad
const randomName = goog.require('something.else'); // name must match
const {clear, forEach, map} = // don't break lines
goog.require('goog.array');
function someFunction() {
const alias = goog.require('my.long.name.alias'); // must be at top level
// …
}
// good
const MyClass = goog.require('some.package.MyClass');
const NsMyClass = goog.require('other.ns.MyClass');
const googAsserts = goog.require('goog.asserts');
const testingAsserts = goog.require('goog.testing.asserts');
const than80columns = goog.require('pretend.this.is.longer.than80columns');
const {clear, forEach, map} = goog.require('goog.array');
/** @suppress {extraRequire} Initializes MyFramework. */
goog.require('my.framework.initialization');
goog.forwardDeclare
goog.forwardDeclare
is not needed very often, but is a valuable tool to break circular dependencies or to reference late loaded code. These statements are grouped together and immediately follow any goog.require
statements. A goog.forwardDeclare
statement must follow the same style rules as a goog.require
statement.
The actual implementation follows after all dependency information is declared (separated by at least one blank line).
This may consist of any module-local declarations (constants, variables, classes, functions, etc), as well as any exported symbols.
Braces are required for all control structures, even if the body contains only a single statement. The first statement of a non-empty block must begin on its own line.
// bad
if (someVeryLongCondition())
doSomething();
for (let i = 0; i < foo.length; i++) bar(foo[i]);
// good
if (shortCondition()) return;
Braces follow the Kernighan and Ritchie style (Egyptian brackets) for nonempty blocks and block-like constructs:
else
, catch
, while
, or a comma, semicolon, or right-parenthesis.class InnerClass {
constructor() {}
/** @param {number} foo */
method(foo) {
if (condition(foo)) {
try {
// Note: this might fail.
something();
} catch (err) {
recover();
}
}
}
}
An empty block or block-like construct may be closed immediately after it is opened, with no characters, space, or line break in between (i.e. {}
), unless it is a part of a multi-block statement (one that directly contains multiple blocks: if
/else
or try
/catch
/finally
).
// bad
if (condition) {
// …
} else if (otherCondition) {} else {
// …
}
try {
// …
} catch (e) {}
// good
function doNothing() {}
Any array literal may optionally be formatted as if it were a “block-like construct.”
// good
const a = [
0,
1,
2,
];
const b =
[0, 1, 2];
const c = [0, 1, 2];
someMethod(foo, [
0, 1, 2,
], bar);
Any object literal may optionally be formatted as if it were a “block-like construct”.
// good
const a = {
a: 0,
b: 1,
};
const b =
{a: 0, b: 1};
const c = {a: 0, b: 1};
someMethod(foo, {
a: 0, b: 1,
}, bar);
Use the extends
keyword, but not the @extends
JSDoc annotation unless the class extends a templatized type.
// good
class Foo {
constructor() {
/** @type {number} */
this.x = 42;
}
/** @return {number} */
method() {
return this.x;
}
}
Foo.Empty = class {};
/** @extends {Foo<string>} */
foo.Bar = class extends Foo {
/** @override */
method() {
return super.method() / 2;
}
};
/** @interface */
class Frobnicator {
/** @param {string} message */
frobnicate(message) {}
}
When declaring an anonymous function in the list of arguments for a function call, the body of the function is indented two spaces more than the preceding indentation depth.
prefix.something.reallyLongFunctionName('whatever', (a1, a2) => {
// Indent the function body +2 relative to indentation depth
// of the 'prefix' statement one line above.
if (a1.equals(a2)) {
someOtherLongFunctionName(a1);
} else {
andNowForSomethingCompletelyDifferent(a2.parrot);
}
});
some.reallyLongFunctionCall(arg1, arg2, arg3)
.thatsWrapped()
.then((result) => {
// Indent the function body +2 relative to the indentation depth
// of the '.then()' call.
if (result) {
result.use();
}
});
As with any other block, the contents of a switch block are indented +2.
An explicit block may be used if required by lexical scoping.
switch (animal) {
case Animal.BANDERSNATCH: {
handleBandersnatch();
break;
}
case Animal.JABBERWOCK: {
handleJabberwock();
break;
}
default: {
throw new Error('Unknown animal');
}
}
Every statement must be terminated with a semicolon. Relying on automatic semicolon insertion is forbidden.
The prime directive of line-wrapping is: prefer to break at a higher syntactic level.
// bad
currentEstimate = calc(currentEstimate + x *
currentEstimate) / 2.0f;
// good
currentEstimate =
calc(currentEstimate + x * currentEstimate) /
2.0f;
When line-wrapping, each line after the first (each continuation line) is indented at least +4 from the original line, unless it falls under the rules of block indentation.
Trailing whitespace is forbidden.
Separating any reserved word (such as if
, for
, or catch
) from an open parenthesis ((
) that follows it on that line.
// good
if (something)
Separating any reserved word (such as else
or catch
) from a closing curly brace (}
) that precedes it on that line.
else {
Before any open curly brace ({
), with two exceptions:
`foo({a: [{c: d}]})
const str = `abc${1 + 2}def`;
On both sides of any binary or ternary operator.
const a = isGood ? 'good' : 'bad';
After a comma (,
) or semicolon (;
). Note that spaces are never allowed before these characters.
const arr = [1, 2];
After the colon (:
) in an object literal.
const obj = {a: 1, b: 2};
On both sides of the double slash (//
) that begins an end-of-line comment. Here, multiple spaces are allowed, but not required.
const a = 1; // comment
After an open-JSDoc comment character and on both sides of close characters.
this.foo = /** @type {number} */ (bar);
function(/** string */ foo) {}
It is generally discouraged.
Prefer to put all function arguments on the same line as the function name.
To save space, you may wrap as close to 80 as possible, or put each argument on its own line to enhance readability. Indentation should be four spaces.
// Arguments start on a new line, indented four spaces. Preferred when the
// arguments don't fit on the same line with the function name (or the keyword
// "function") but fit entirely on the second line. Works with very long
// function names, survives renaming without reindenting, low on space.
doSomething(
descriptiveArgumentOne, descriptiveArgumentTwo, descriptiveArgumentThree) {
// …
}
// If the argument list is longer, wrap at 80. Uses less vertical space,
// but violates the rectangle rule and is thus not recommended.
doSomething(veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo,
tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) {
// …
}
// Four-space, one argument per line. Works with long function names,
// survives renaming, and emphasizes each argument.
doSomething(
veryDescriptiveArgumentNumberOne,
veryDescriptiveArgumentTwo,
tableModelEventHandlerProxy,
artichokeDescriptorAdapterIterator) {
// …
}
Do not use unnecessary parentheses around the entire expression following delete
, typeof
, void
, return
, throw
, case
, in
, of
, or yield
.
Parentheses are required for type casts.
/** @type {!Foo} */ (foo)
Block comments are indented at the same level as the surrounding code. They may be in /* … */
or //
-style. For multi-line /* … */
comments, subsequent lines must start with *
aligned with the *
on the previous line, to make comments obvious with no extra context. “Parameter name” comments should appear after values whenever the value and method name do not sufficiently convey the meaning.
/*
* This is
* okay.
*/
// And so
// is this.
/* This is fine, too. */
someFunction(obviousParam, true /* shouldRender */, 'hello' /* name */);
const
and let
Declare all local variables with either const
or let
. Use const
by default, unless a variable needs to be reassigned. The var
keyword must not be used.
Every local variable declaration declares only one variable.
// bad
let a = 1, b = 2;
JSDoc type annotations may be added either on the line above the declaration, or else inline before the variable name.
const /** !Array<number> */ data = [];
/** @type {!Array<number>} */
const data = [];
const values = [
'first value',
'second value',
];
Array
constructor// bad
const a1 = new Array(x1, x2, x3);
const a2 = new Array(x1, x2);
const a3 = new Array(x1);
const a4 = new Array();
// good
const a1 = [x1, x2, x3];
const a2 = [x1, x2];
const a3 = [x1];
const a4 = [];
Do not define or use non-numeric properties on an array (other than length
). Use a Map
(or Object
) instead.
Array literals may be used on the left-hand side of an assignment to perform destructuring.
A final rest
element may be included (with no space between the ...
and the variable name).
// bad
function badDestructuring([a, b] = [4, 2]) { … };
// good
const [a, b, c, ...rest] = generateResults();
let [, b,, d] = someArray;
Destructuring may also be used for function parameters (note that a parameter name is required but ignored). Always specify []
as the default value if a destructured array parameter is optional, and provide default values on the left hand side.
/** @param {!Array<number>=} param1 */
function optionalDestructuring([a = 4, b = 2] = []) { … };
Array literals may include the spread operator (...
) to flatten elements out of one or more other iterables. The spread operator should be used instead of more awkward constructs with Array.prototype
. There is no space after the ...
.
[...foo] // preferred over Array.prototype.slice.call(foo)
[...foo, ...bar] // preferred over foo.concat(bar)
Object
constructorconst obj = {['key' + foo()]: 42};
return {
stuff: 'candy',
method() {
return this.stuff; // Returns 'candy'
},
};
const foo = 1;
const bar = 2;
const obj = {
foo,
bar,
method() { return this.foo + this.bar; },
};
assertEquals(3, obj.method());
Destructured objects may also be used as function parameters, but should be kept as simple as possible: a single level of unquoted shorthand properties.
Specify any default values in the left-hand-side of the destructured parameter ({str = 'some default'} = {}
, rather than {str} = {str: 'some default'}
).
If a destructured object is itself optional, it must default to {}
.
// bad
/** @param {{x: {num: (number|undefined), str: (string|undefined)}}} param1 */
function nestedTooDeeply({x: {num, str}}) {};
/** @param {{num: (number|undefined), str: (string|undefined)}=} param1 */
function nonShorthandProperty({num: a, str: b} = {}) {};
/** @param {{a: number, b: number}} param1 */
function computedKey({a, b, [a + b]: c}) {};
/** @param {{a: number, b: string}=} param1 */
function nontrivialDefault({a, b} = {a: 2, b: 4}) {};
// good
/**
* @param {string} ordinary
* @param {{num: (number|undefined), str: (string|undefined)}=} param1
* num: The number of times to do something.
* str: A string to do stuff to.
*/
function destructured(ordinary, {num, str = 'some default'} = {})
Enumerations are defined by adding the @enum
annotation to an object literal. Additional properties may not be added to an enum after it is defined. Enums must be constant, and all enum values must be deeply immutable.
/**
* Supported temperature scales.
* @enum {string}
*/
const TemperatureScale = {
CELSIUS: 'celsius',
FAHRENHEIT: 'fahrenheit',
};
/**
* An enum with two options.
* @enum {number}
*/
const Option = {
/** The option used shall have been the first. */
FIRST_OPTION: 1,
/** The second among two options. */
SECOND_OPTION: 2,
};
super()
before setting any fields or otherwise accessing this
.@const
(these need not be deeply immutable).@private
and their names must end with a trailing underscore.prototype
.class Foo {
constructor() {
/** @private @const {!Bar} */
this.bar_ = computeBar();
}
}
Computed properties may only be used in classes when the property is a symbol. A [Symbol.iterator]
method should be defined for any classes that are logically iterable. Beyond this, Symbol
should be used sparingly.
Where it does not interfere with readability, prefer module-local functions over private static methods.
@nocollapse
if this is done), and must not be called directly on a subclass that doesn’t define the method itself.// bad
class Base { /** @nocollapse */ static foo() {} }
class Sub extends Base {}
function callFoo(cls) { cls.foo(); } // discouraged: don't call static methods dynamically
Sub.foo(); // illegal: don't call static methods on subclasses that don't define it themselves
While ES6 classes are preferred, there are cases where ES6 classes may not be feasible.
If there exist or will exist subclasses, including frameworks that create subclasses, that cannot be immediately changed to use ES6 class syntax. If such a class were to use ES6 syntax, all downstream subclasses not using ES6 class syntax would need to be modified.
Frameworks that require a known this
value before calling the superclass constructor, since constructors with ES6 super classes do not have access to the instance this
value until the call to super
returns.
prototypes
directlyThe class
keyword allows clearer and more readable class definitions than defining prototype
properties.
Do not use JavaScript getter and setter properties. They are potentially surprising and difficult to reason about, and have limited support in the compiler. Provide ordinary methods instead.
Getters must not change observable state.
// bad
class Foo {
get next() { return this.nextId++; }
}
toString
The toString
method may be overridden, but must always succeed and never have visible side effects.
Beware, in particular, of calling other methods from toString
, since exceptional conditions could lead to infinite loops.
Interfaces may be declared with @interface
or @record
. Interfaces declared with @record
can be explicitly (i.e. via @implements
) or implicitly implemented by a class or object literal.
All non-static method bodies on an interface must be empty blocks. Fields must be defined after the interface body as stubs on the prototype
.
**
* Something that can frobnicate.
* @record
*/
class Frobnicator {
/**
* Performs the frobnication according to the given strategy.
* @param {!FrobnicationStrategy} strategy
*/
frobnicate(strategy) {}
}
/** @type {number} The number of attempts before giving up. */
Frobnicator.prototype.attempts;
Exported functions may be defined directly on the exports
object, or else declared locally and exported separately.
Non-exported functions are encouraged and should not be declared @private
.
/** @return {number} */
function helperFunction() {
return 42;
}
/** @return {number} */
function exportedFunction() {
return helperFunction() * 2;
}
/**
* @param {string} arg
* @return {number}
*/
function anotherExportedFunction(arg) {
return helperFunction() / arg.length;
}
/** @const */
exports = {exportedFunction, anotherExportedFunction};
/** @param {string} arg */
exports.foo = (arg) => {
// do some stuff ...
};
Functions may contain nested function definitions. If it is useful to give the function a name, it should be assigned to a local const
.
Arrow functions provide a concise syntax and fix a number of difficulties with this
. Prefer arrow functions over the function
keyword, particularly for nested functions.
Prefer using arrow functions over f.bind(this)
. Avoid writing const self = this
. Arrow functions are particularly useful for callbacks, which sometimes pass unexpected additional arguments.
The right-hand side of the arrow may be a single expression or a block. Parentheses around the arguments are optional if there is only a single non-destructured argument. It is a good practice to use parentheses even for single-argument arrows, since the code may still parse reasonably (but incorrectly) if the parentheses are forgotten when an additional argument is added.
Generators enable a number of useful abstractions and may be used as needed.
When defining generator functions, attach the *
to the function
keyword when present, and separate it with a space from the name of the function. When using delegating yields, attach the *
to the yield
keyword.
/** @return {!Iterator<number>} */
function* gen1() {
yield 42;
}
/** @return {!Iterator<number>} */
const gen2 = function*() {
yield* gen1();
}
class SomeClass {
/** @return {!Iterator<number>} */
* gen() {
yield 42;
}
}
Function parameters must be typed with JSDoc annotations in the JSDoc preceding the function’s definition, except in the case of same-signature @override
, where all types are omitted.
Parameter types may be specified inline, immediately before the parameter name.
(/** number */ foo, /** string */ bar) => foo + bar
Inline and @param
type annotations must not be mixed in the same function definition.
opt_
), use the =
suffix in their JSDoc type, come after required parameters, and not use initializers that produce observable side effects.undefined
./**
* @param {string} required This parameter is always needed.
* @param {string=} optional This parameter can be omitted.
* @param {!Node=} node Another optional parameter.
*/
function maybeDoSomething(required, optional = '', node = undefined) {}
Use default parameters sparingly. Prefer destructuring to create readable APIs when there are more than a small handful of optional parameters that do not have a natural order.
Use a rest parameter instead of accessing arguments. Rest parameters are typed with a ...
prefix in their JSDoc. The rest parameter must be the last parameter in the list. There is no space between the ...
and the parameter name. Do not name the rest parameter var_args
. Never name a local variable or parameter arguments
, which confusingly shadows the built-in name.
/**
* @param {!Array<string>} array This is an ordinary parameter.
* @param {...number} numbers The remainder of arguments are all numbers.
*/
function variadic(array, ...numbers) {}
Function return types must be specified in the JSDoc directly above the function definition, except in the case of same-signature @override
where all types are omitted.
Declare generic functions and methods when necessary with @template TYPE
in the JSDoc above the class definition.
Function calls may use the spread operator (...
). Prefer the spread operator to Function.prototype.apply
when an array or iterable is unpacked into multiple parameters of a variadic function. There is no space after the ...
.
function myFunction(...elements) {}
myFunction(...array, ...iterable, ...generator());
Ordinary string literals may not span multiple lines.
Template strings may span multiple lines.
If a template string spans multiple lines, it does not need to follow the indentation of the enclosing block, though it may if the added whitespace does not matter.
function arithmetic(a, b) {
return `Here is a table of arithmetic operations:
${a} + ${b} = ${a + b}
${a} - ${b} = ${a - b}
${a} * ${b} = ${a * b}
${a} / ${b} = ${a / b}`;
}
Do not use line continuations (that is, ending a line inside a string literal with a backslash) in either ordinary or template string literals. Even though ES5 allows this, it can lead to tricky errors if any trailing whitespace comes after the slash, and is less obvious to readers.
// bad
const longString = 'This is a very long string that far exceeds the 80 \
column limit. It unfortunately contains long stretches of spaces due \
to how the continued lines are indented.';
// good
const longString = 'This is a very long string that far exceeds the 80 ' +
'column limit. It does not contain long stretches of spaces since ' +
'the concatenated strings are cleaner.';
Numbers may be specified in decimal, hex, octal, or binary. Use exactly 0x
, 0o
, and 0b
prefixes, with lowercase letters, for hex, octal, and binary, respectively. Never include a leading zero unless it is immediately followed by x
, o
, or b
.
With ES6, the language now has three different kinds of for
loops. All may be used, though for-of
loops should be preferred when possible.
for-in
loops may only be used on dict-style objects, and should not be used to iterate over an array.Object.prototype.hasOwnProperty
should be used in for-in
loops to exclude unwanted prototype properties.for-of
and Object.keys
over for-in
when possible.Always throw Errors
or subclasses of Error
: never throw string literals or other objects. Always use new
when constructing an Error
.
Custom exceptions provide a great way to convey additional error information from functions. They should be defined and used wherever the native Error
type is insufficient.
Prefer throwing exceptions over ad-hoc error-handling approaches (such as passing an error container reference type, or returning an object with an error property).
It is very rarely correct to do nothing in response to a caught exception. When it truly is appropriate to take no action whatsoever in a catch
block, the reason this is justified is explained in a comment.
// bad
try {
shouldFail();
fail('expected an error');
} catch (expected) {}
// good
try {
return handleNumericResponse(response);
} catch (ok) {
// it's not numeric; that's fine, just continue
}
return handleTextResponse(response);
Any comment that communicates the idea of fall-through is sufficient (typically // fall through
). This special comment is not required in the last statement group of the switch block.
switch (input) {
case 1:
case 2:
prepareOneOrTwo();
// fall through
case 3:
handleOneTwoOrThree();
break;
default:
handleLargeNumber(input);
}
Each switch statement includes a default
statement group, even if it contains no code.
this
Only use this
in class constructors and methods, or in arrow functions defined within class constructors and methods. Any other uses of this
must have an explicit @this
declared in the immediately-enclosing function’s JSDoc.
Never use this
to refer to the global object, the context of an eval
, the target of an event, or unnecessarily call()
ed or apply()
ed functions.
Do not use the with
keyword. It makes your code harder to understand and has been banned in strict mode since ES5.
Do not use eval
or the Function(...string)
constructor (except for code loaders). These features are potentially dangerous and simply do not work in CSP environments.
Always terminate statements with semicolons.
Do not use non-standard features. This includes old features that have been removed (e.g., WeakMap.clear
), new features that are not yet standardized (e.g., the current TC39 working draft, proposals at any stage, or proposed but not-yet-complete web standards), or proprietary features that are only implemented in some browsers.
Never use new
on the primitive object wrappers (Boolean
, Number
, String
, Symbol
), nor include them in type annotations.
// bad
const /** Boolean */ x = new Boolean(false);
if (x) alert(typeof x); // alerts 'object' - WAT?
// good
const /** boolean */ x = Boolean(0);
if (!x) alert(typeof x); // alerts 'boolean', as expected
Never modify builtin types, either by adding methods to their constructors or to their prototypes. Avoid depending on libraries that do this.
Do not add symbols to the global object unless absolutely necessary (e.g. required by a third-party API).
Give as descriptive a name as possible, within reason. Do not use abbreviations that are ambiguous or unfamiliar to readers outside your project, and do not abbreviate by deleting letters within a word.
// bad
n // Meaningless.
nErr // Ambiguous abbreviation.
nCompConns // Ambiguous abbreviation.
wgcConnections // Only your group knows what this stands for.
pcReader // Lots of things can be abbreviated "pc".
cstmrId // Deletes internal letters.
kSecondsPerDay // Do not use Hungarian notation.
// good
priceCountReader // No abbreviation.
numErrors // "num" is a widespread convention.
numDnsConnections // Most people know what "DNS" stands for.
Package names are all lowerCamelCase
. For example, my.exampleCode.deepSpace
, but not my.examplecode.deepspace
or my.example_code.deep_space
.
Class, interface, record, and typedef names are written in UpperCamelCase
. Unexported classes are simply locals: they are not marked @private
and therefore are not named with a trailing underscore.
Type names are typically nouns or noun phrases. For example, Request
, ImmutableList
, or VisibilityMode
. Additionally, interface names may sometimes be adjectives or adjective phrases instead (for example, Readable
).
Method names are written in lowerCamelCase
. Private methods’ names must end with a trailing underscore.
Method names are typically verbs or verb phrases. For example, sendMessage
or stop_
. Getter and setter methods for properties are never required, but if they are used they should be named getFoo
(or optionally isFoo
or hasFoo
for booleans), or setFoo(value)
for setters.
Underscores may also appear in JsUnit test method names to separate logical components of the name. One typical pattern is test<MethodUnderTest>_<state>
, for example testPop_emptyStack
. There is no One Correct Way to name test methods.
Enum names are written in UpperCamelCase
, similar to classes, and should generally be singular nouns. Individual items within the enum are named in CONSTANT_CASE
.
Constant names use CONSTANT_CASE
: all uppercase letters, with words separated by underscores. There is no reason for a constant to be named with a trailing underscore, since private static properties can be replaced by (implicitly private) module locals.
Every constant is a @const
static property or a module-local const declaration, but not all @const
static properties and module-local const
s are constants. Before choosing constant case, consider whether the field really feels like a deeply immutable constant.
// Constants
const NUMBER = 5;
/** @const */ exports.NAMES = ImmutableList.of('Ed', 'Ann');
/** @enum */ exports.SomeEnum = { ENUM_CONSTANT: 'value' };
// Not constants
let letVariable = 'non-const';
class MyClass { constructor() { /** @const */ this.nonStatic = 'non-static'; } };
/** @type {string} */ MyClass.staticButMutable = 'not @const, can be reassigned';
const /** Set<String> */ mutableCollection = new Set();
const /** ImmutableSet<SomeMutableType> */ mutableElements = ImmutableSet.of(mutable);
const Foo = goog.require('my.Foo'); // mirrors imported name
const logger = log.getLogger('loggers.are.not.immutable');
Local aliases should be used whenever they improve readability over fully-qualified names. Aliases may also be used within functions. Aliases must be const
.
const staticHelper = importedNamespace.staticHelper;
const CONSTANT_NAME = ImportedClass.CONSTANT_NAME;
const {assert, assertInstanceof} = asserts;
Non-constant field names (static or otherwise) are written in lowerCamelCase
, with a trailing underscore for private fields.
These names are typically nouns or noun phrases. For example, computedValues
or index_
.
Parameter names are written in lowerCamelCase
. Note that this applies even if the parameter expects a constructor.
One-character parameter names should not be used in public methods.
Local variable names are written in lowerCamelCase
, except for module-local (top-level) constants, as described above. Constants in function scopes are still named in lowerCamelCase
.
Template parameter names should be concise, single-word or single-letter identifiers, and must be all-caps, such as TYPE
or THIS
.
Note: This is different than Airbnb guide.
XMLHTTPRequest // bad
XmlHttpRequest // good
newCustomerID // bad
newCustomerId // good
innerStopWatch // bad
innerStopwatch // good
supportsIPv6OnIOS // bad
supportsIpv6OnIos // good
YoutubeImporter // bad
YouTubeImporter // good
/**
* Multiple lines of JSDoc text are written here,
* wrapped normally.
* @param {number} arg A number to do something to.
*/
function doSomething(arg) { … }
/** @const @private {!Foo} A short bit of JSDoc. */
this.foo_ = foo;
/**
* Computes weight based on three factors:
* - items sent
* - items received
* - last timestamp
*/
// bad
/**
* The "param" tag must occupy its own line and may not be combined.
* @param {number} left @param {number} right
*/
function add(left, right) { ... }
// good
/**
* Place more complex annotations (like "implements" and "template")
* on their own lines. Multiple simple tags (like "export" and "final")
* may be combined in one line.
* @export @final
* @implements {Iterable<TYPE>}
* @template TYPE
*/
class MyClass {
/**
* @param {!ObjType} obj Some object.
* @param {number=} num An optional number.
*/
constructor(obj, num = 42) {
/** @private @const {!Array<!ObjType|number>} */
this.data_ = [obj, num];
}
}
Line-wrapped block tags are indented four spaces. Wrapped description text may be lined up with the description on previous lines, but this horizontal alignment is discouraged.
/**
* Illustrates line wrapping for long param/return descriptions.
* @param {string} foo This is a param with a description too long to fit in
* one line.
* @return {number} This returns something that has a description too long to
* fit in one line.
*/
exports.method = function(foo) {
return 5;
};
A file may have a top-level file overview. A copyright notice, author information, and default visibility level are optional. File overviews are generally recommended whenever a file consists of more than a single class definition. The top level comment is designed to orient readers unfamiliar with the code to what is in this file. If present, it may provide a description of the file's contents and any dependencies or compatibility information. Wrapped lines are not indented.
/**
* @fileoverview Description of file, its uses and information
* about its dependencies.
* @package
*/
Classes, interfaces and records must be documented with a description and any template parameters, implemented interfaces, visibility, or other appropriate tags. The class description should provide the reader with enough information to know how and when to use the class, as well as any additional considerations necessary to correctly use the class. Textual descriptions may be omitted on the constructor. @constructor
and @extends
annotations are not used with the class
keyword unless the class is being used to declare an @interface
or it extends a generic class.
/**
* A fancier event target that does cool things.
* @implements {Iterable<string>}
*/
class MyFancyTarget extends EventTarget {
/**
* @param {string} arg1 An argument that makes this more interesting.
* @param {!Array<number>} arg2 List of numbers to be processed.
*/
constructor(arg1, arg2) {
// ...
}
};
/**
* Records are also helpful.
* @extends {Iterator<TYPE>}
* @record
* @template TYPE
*/
class Listable {
/** @return {TYPE} The next item in line to be returned. */
next() {}
}
Enums and typedefs must be documented. Public enums and typedefs must have a non-empty description. Individual enum items may be documented with a JSDoc comment on the preceding line.
/**
* A useful type union, which is reused often.
* @typedef {!Bandersnatch|!BandersnatchType}
*/
let CoolUnionType;
/**
* Types of bandersnatches.
* @enum {string}
*/
const BandersnatchType = {
/** This kind is really frumious. */
FRUMIOUS: 'frumious',
/** The less-frumious kind. */
MANXOME: 'manxome',
};
this
type should be documented when necessary.@override
annotation. Overridden methods must include all @param
and @return
annotations if any types are refined, but should omit them if the types are all the same./** This is a class. */
class SomeClass extends SomeBaseClass {
/**
* Operates on an instance of MyClass and returns something.
* @param {!MyClass} obj An object that for some reason needs detailed
* explanation that spans multiple lines.
* @param {!OtherClass} obviousOtherClass
* @return {boolean} Whether something occurred.
*/
someMethod(obj, obviousOtherClass) { ... }
/** @override */
overriddenMethod(param) { ... }
}
/**
* Demonstrates how top-level functions follow the same rules. This one
* makes an array.
* @param {TYPE} arg
* @return {!Array<TYPE>}
* @template TYPE
*/
function makeArray(arg) { ... }
Anonymous functions do not require JSDoc, though parameter types may be specified inline if the automatic type inference is insufficient.
promise.then(
(/** !Array<number|string> */ items) => {
doSomethingWith(items);
return /** @type {string} */ (items[0]);
});
Property types must be documented. The description may be omitted for private properties, if name and type provide enough documentation for understanding the code.
Publicly exported constants are commented the same way as properties. Explicit types may be omitted for @const
properties initialized from an expression with an obviously known type.
/** My class. */
class MyClass {
/** @param {string=} someString */
constructor(someString = 'default string') {
/** @private @const */
this.someString_ = someString;
/** @private @const {!OtherType} */
this.someOtherThing_ = functionThatReturnsAThing();
/**
* Maximum number of things per pane.
* @type {number}
*/
this.someProperty = 4;
}
}
/**
* The number of times we'll try before giving up.
* @const
*/
MyClass.RETRY_COUNT = 33;
Type annotations are found on @param
, @return
, @this
, and @type
tags, and optionally on @const
, @export
, and any visibility tags. Type annotations attached to JSDoc tags must always be enclosed in braces.
The type system defines modifiers !
and ?
for non-null and nullable, respectively. Primitive types (undefined
, string
, number
, boolean
, symbol
, and function(...): ...
) and record literals ({foo: string, bar: number}
) are non-null by default. Do not add an explicit !
to these types. Object types (Array
, Element
, MyClass
, etc) are nullable by default, but cannot be immediately distinguished from a name that is @typedef
’d to a non-null-by-default type. As such, all types except primitives and record literals must be annotated explicitly with either ?
or !
to indicate whether they are nullable or not.
In cases where type checking doesn't accurately infer the type of an expression, it is possible to tighten the type by adding a type annotation comment and enclosing the expression in parentheses. Note that the parentheses are required.
/** @type {number} */ (x)
Always specify template parameters. This way compiler can do a better job and it makes it easier for readers to understand what code does.
// bad
const /** !Object */ users = {};
const /** !Array */ books = [];
const /** !Promise */ response = ...;
// good
const /** !Object<string, !User> */ users = {};
const /** !Array<string> */ books = [];
const /** !Promise<!Response> */ response = ...;
const /** !Promise<undefined> */ thisPromiseReturnsNothingButParameterIsStillUseful = ...;
const /** !Object<string, *> */ mapOfEverything = {};
Visibility annotations (@private
, @package
, @protected
) may be specified in a @fileoverview
block, or on any exported symbol or property. Do not specify visibility for local variables, whether within a function or at the top level of a module. All @private
names must end with an underscore.
As far as possible projects should use --warning_level=VERBOSE
.
Before doing anything, make sure you understand exactly what the warning is telling you.
Once you understand the warning, attempt the following solutions in order:
@suppress
annotation.Warnings are suppressed at the narrowest reasonable scope, usually that of a single local variable or very small method. Often a variable or method is extracted for that reason alone.
/** @suppress {uselessCode} Unrecognized 'use asm' declaration */
function fn() {
'use asm';
return 0;
}
Even a large number of suppressions in a class is still better than blinding the entire class to this type of warning.
Mark deprecated methods, classes or interfaces with @deprecated
annotations. A deprecation comment must include simple, clear directions for people to fix their call sites.
You will occasionally encounter files in your codebase that are not in proper Google Style. These may have come from an acquisition, or may have been written before Google Style took a position on some issue, or may be in non-Google Style for any other reason.
When updating the style of existing code, follow these guidelines.
Brand new files use Google Style, regardless of the style choices of other files in the same package.
When adding new code to a file that is not in Google Style, reformatting the existing code first is recommended.
If this reformatting is not done, then new code should be as consistent as possible with existing code in the same file, but must not violate the style guide.
eams and projects may adopt additional style rules beyond those in this document, but must accept that cleanup changes may not abide by these additional rules, and must not block such cleanup changes due to violating any additional rules. Beware of excessive rules which serve no purpose. The style guide does not seek to define style in every possible scenario and neither should you.
Source code generated by the build process is not required to be in Google Style. However, any generated identifiers that will be referenced from hand-written source code must follow the naming requirements. As a special exception, such identifiers are allowed to contain underscores, which may help to avoid conflicts with hand-written identifiers.
airbnb/javascript: JavaScript Style Guide Google JavaScript Style Guide bendc/frontend-guidelines: Some HTML, CSS and JS best practices.