JavaScript Style Guide
Rules ¶
References ¶
Use const for all of your references; avoid using var [Mandatory] ¶
eslint:
prefer-const,no-const-assign// bad var a = 1; var b = 2; // good const a = 1; const b = 2;
If you must reassign references, use let instead of var [Mandatory] ¶
eslint:
no-var// bad var count = 1; if (true) { count += 1; } // good let count = 1; if (true) { count += 1; }
Variables ¶
Always use const or let to declare variables [Mandatory] ¶
eslint:
no-undefprefer-const// bad superPower = new SuperPower(); good const superPower = new SuperPower();
Disallow unused variables. [Mandatory] ¶
eslint:
no-unused-vars// bad var some_unused_var = 42; // Write-only variables are not considered as used. var y = 10; y = 5; // A read for a modification of itself is not considered as used. var z = 0; z = z + 1; // Unused function arguments. function getX(x, y) { return x; } // good function getXPlusY(x, y) { return x + y; } var x = 1; var y = a + 2; alert(getXPlusY(x, y)); // 'type' is ignored even if unused because it has a rest property sibling. // This is a form of extracting an object that omits the specified keys. var { type, ...coords } = data; // 'coords' is now the 'data' object without its 'type' property.
Avoid using unary increments and decrements (++, --) [Recommended] ¶
// bad const array = [1, 2, 3]; let num = 1; num++; --num; let sum = 0; let truthyCount = 0; for (let i = 0; i < array.length; i++) { let value = array[i]; sum += value; if (value) { truthyCount++; } } // good const array = [1, 2, 3]; let num = 1; num += 1; num -= 1; const sum = array.reduce((a, b) => a + b, 0); const truthyCount = array.filter(Boolean).length;
Quotes ¶
Only quote properties that are invalid identifiers [Mandatory] ¶
eslint:
quote-props// bad const bad = { 'foo': 3, 'bar': 4, 'data-blah': 5, }; // good const good = { foo: 3, bar: 4, ‘data-blah’: 5, };
Use single quotes ' ' for strings [Mandatory] ¶
eslint:
quotes// bad const name = "Capt. Janeway"; // bad - template literals should contain interpolation or newlines const name = `Capt. Janeway`; // good const name = 'Capt. Janeway';
When programmatically building up strings, use template strings instead of concatenation [Mandatory] ¶
eslint:
prefer-templatetemplate-curly-spacing// bad function sayHi(name) { return 'How are you, ' + name + '?'; } // bad function sayHi(name) { return ['How are you, ', name, '?'].join(); } // bad function sayHi(name) { return `How are you, ${ name }?`; } // good function sayHi(name) { return `How are you, ${name}?`; }
Destructuring ¶
Use object destructuring when accessing and using multiple properties of an object. [Mandatory] ¶
eslint:
prefer-destructuring// bad function getFullName(user) { const firstName = user.firstName; const lastName = user.lastName; return `${firstName} ${lastName}`; } // good function getFullName(user) { const { firstName, lastName } = user; return `${firstName} ${lastName}`; } // best function getFullName({ firstName, lastName }) { return `${firstName} ${lastName}`; }
Use array destructuring [Recommended] ¶
const arr = [1, 2, 3, 4]; // bad const first = arr[0]; const second = arr[1]; // good const [first, second] = arr;
No eval ¶
Never use eval() on a string, it opens too many vulnerabilities [Mandatory] ¶
eslint:
no-eval
Functions ¶
Always put default parameters last [Mandatory] ¶
eslint:
default-param-last// bad function handleThings(opts = {}, name) { // ... } // good function handleThings(name, opts = {}) { // ... }
Spacing in a function signature. [Mandatory] ¶
eslint:
space-before-function-parenspace-before-blocks// bad const f = function(){}; const g = function (){}; const h = function() {}; // good const x = function () {}; const y = function a() {};
Arrow Functions ¶
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. [Mandatory] ¶
eslint:
arrow-parensarrow-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 + 1}.`); // good [1, 2, 3].map((number) => { const nextNumber = number + 1; return `A string containing the ${nextNumber}.`; }); // good [1, 2, 3].map((number, index) => ({ [index]: number, })); // No implicit return with side effects function foo(callback) { const val = callback(); if (val === true) { // Do something if callback returns true } } let bool = false; // bad foo(() => bool = true); // good foo(() => { bool = true; });
Always include parentheses around arguments for clarity and consistency. [Recommended] ¶
// bad [1, 2, 3].map(x => x * x); // good [1, 2, 3].map((x) => x * x); // bad [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!` )); // 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; });
Iterators and Generators ¶
Don’t use iterators. Prefer JavaScript’s higher-order functions instead of loops like for-in or for-of. [Recommended] ¶
const numbers = [1, 2, 3, 4, 5]; // bad let sum = 0; for (let num of numbers) { sum += num; } sum === 15; // good let sum = 0; numbers.forEach((num) => { sum += num; }); sum === 15; // best (use the functional force) const sum = numbers.reduce((total, num) => total + num, 0); sum === 15; // bad const increasedByOne = []; for (let i = 0; i < numbers.length; i++) { increasedByOne.push(numbers[i] + 1); } // good const increasedByOne = []; numbers.forEach((num) => { increasedByOne.push(num + 1); }); // best (keeping it functional) const increasedByOne = numbers.map((num) => num + 1);
Comparison Operators & Equality ¶
Use === and !== over == and != [Mandatory] ¶
eslint:
eqeqeq
Use shortcuts for booleans, but explicit comparisons for strings and numbers. [Recommended] ¶
// bad if (isValid === true) { // ... } // good if (isValid) { // ... } // bad if (name) { // ... } // good if (name !== '') { // ... } // bad if (collection.length) { // ... } // good if (collection.length > 0) { // ... }
Blocks ¶
Use braces with all multiline blocks. [Mandatory] ¶
eslint:
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; }
If you’re using multiline blocks with if and else, put else on the same line as your if block’s closing brace. [Mandatory] ¶
eslint:
brace-style// bad if (test) { thing1(); thing2(); } else { thing3(); } // good if (test) { thing1(); thing2(); } else { thing3(); }
Control Statements ¶
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. [Recommended] ¶
// bad if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) { thing1(); } // bad if (foo === 123 && bar === 'abc') { thing1(); } // bad if (foo === 123 && bar === 'abc') { thing1(); } // bad if ( foo === 123 && bar === 'abc' ) { thing1(); } // good if ( foo === 123 && bar === 'abc' ) { thing1(); } // good if ( (foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening() ) { thing1(); } // good if (foo === 123 && bar === 'abc') { thing1(); }
Whitespace ¶
Use soft tabs (space character) set to 2 spaces. [Mandatory] ¶
eslint:
indent// bad function foo() { ∙∙∙∙let name; } // bad function bar() { ∙let name; } // good function baz() { ∙∙let name; }
Place 1 space before the leading brace. [Mandatory] ¶
eslint:
space-before-blocks// bad function test(){ console.log('test'); } // good function test() { console.log('test'); } // bad dog.set('attr',{ age: '1 year', breed: 'Bernese Mountain Dog', }); // good dog.set('attr', { age: '1 year', breed: 'Bernese Mountain Dog', });
Set off operators with spaces. [Mandatory] ¶
eslint:
space-infix-ops// bad const x=y+5; // good const x = y + 5;
Add spaces inside curly braces. [Mandatory] ¶
eslint:
object-curly-spacing// bad const foo = {clark: 'kent'}; // good const foo = { clark: 'kent' };
Naming Conventions ¶
Avoid single letter names. Be descriptive with your naming. [Mandatory] ¶
eslint:
id-length// bad function q() { // ... } // good function query() { // ... }
Use camelCase when naming objects, functions, and instances. [Mandatory] ¶
eslint:
camelCase// bad const OBJEcttsssss = {}; const this_is_my_object = {}; function c() {} // good const thisIsMyObject = {}; function thisIsMyFunction() {}
Setting in project ¶
npx eslint --init ¶
After running npx eslint --init, you’ll have a .eslintrc.{js,yml,json} file in your directory. In it, you’ll see some rules configured like this:
{ "rules": { "semi": ["error", "always"], "quotes": ["error", "double"] } }
Set the rules below in .eslintrc.js ¶
'prefer-const': 'error', 'no-var': 'error', 'no-unused-vars': 'error', 'quote-props': ['error', 'as-needed'], quotes: ['error', 'single'], 'prefer-template': 'error', 'prefer-destructuring': ['error'], 'no-eval': 'error', 'default-param-last': ['error'], 'space-before-function-paren': 'error', 'arrow-parens': ['error', 'always'], eqeqeq: ['error', 'always'], 'nonblock-statement-body-position': ['error', 'beside'], 'brace-style': 'error', 'indent': ['error', 2], 'space-infix-ops': 'error', 'object-curly-spacing': ['error', 'always'], 'id-length': 'error', camelcase: 'error', 'comma-dangle': ['error', 'never'], 'no-plusplus': 1, 'no-iterator': 1