Skip to content

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-undef prefer-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.
// 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-template template-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}`;
}
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-paren space-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-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 + 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;
});
// 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

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

// 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

// 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

References

ESLint

Airbnb JavaScript Style Guide