Стиль кода HTML Academy

github.com/htmlacademy/codeguide

Синтаксис

Отступы, пробелы и переносы

Для правильного форматирования используйте файл .editorconfig в вашем редакторе.

Для отступов используются два пробела. Знак табуляции не используется

При переносах в продолжении строки используется четыре пробела

Запрещено одновременное использование табов и пробелов для отступов

Для отступов ключевых слов, операторов и т. д. используется не более одного пробела

const name       = 1;
const longerName = 2;
const name = 1;
const longerName = 2;

Открывающие скобки блоков кода находятся на одной строке с оператором, который их использует:

if (condition)
{
  // code
}
if (condition) {
  // code
}

В однострочных блоках кода, код отделен от открывающей и закрывающей скобки пробелом

В однострочных массивах скобки не отделяются пробелами, первое значение идёт непосредственно после открывающей скобки, а закрывающая скобка идёт непосредственно после последнего значения массива

После запятой всегда должен ставиться пробел, если запятая не в конце строки

Обязательно переносить запятую на новую строку при объявлении массивов и объектов. Обязательно использовать запятую в конце списков, объектов или перечислений параметров функции

const foo = {
  a: 1,
  b: 2
};

const bar = [
  1,
  2
];
const foo = {
  a: 1,
  b: 2,
};

const bar = [
  1,
  2,
];

Файл должен заканчиваться пустой строкой

Строка не должна заканчиваться пробелами

В однострочных объектах и при деструктуризации фигурные скобки не отделяются пробелами от содержимого

const foo = { a: 1 };
const foo = {a: 1};
const { a, b } = someObject;
const {a, b} = someObject;

Смысловые блоки кода отделяются друг от друга не более чем двумя пустыми строками

В качестве символа переноса строки используется стандартный символ, который используется в системе

При объявлении вычисляемых ключей в объектах с помощью синтаксиса ES2016 в квадратных скобках не используются пробелы

Оператор вызова функции () отделяется пробелом от названия функции

В объектах после объявления ключа не ставится пробел. После двоеточия, которое отделяет в объектах ключ от значения может стоять только один пробел, выравнивать несколько значений при объявлении многострочного объекта запрещено

Ключевые слова отделяются пробелами. Правило касается всех блоков, которые не оговорены отдельно в других правилах. В частности ключевые слова должны отделяться пробелами для условных операторов, циклов, операторов множественного выбора, блоков try..catch, объявлений классов и т. д.

В блоках кода первая и последняя строка не должны быть пустыми (код не отбивается от начала блока кода)

После двоеточий и точек с запятыми ставятся пробелы. Перед ними — не ставятся

Перед скобками начинающими новый блок кода должен ставиться пробел

В комментариях текст отбивается пробелом от начала комментария

При создании генераторов, звездочка идёт сразу после ключевого слова function без пробелов

Звездочка после ключевого слова yield не отбивается пробелом. После звездочки пробел ставится всегда

В spread-операторе точки не отделяются от названия коллекции

Строки

В строках, объявленных с помощью одинарных кавычек, запрещено использовать переносы

В строках запрещено указывать код спецсимволов в восьмеричной системе счисления

const foo = 'Copyright \251';
const foo = 'Copyright \u00A9';

При создании объектов через литералы свойства должны объявляться в едином стиле: или без кавычек или с ними

В строках используются одинарные кавычки. Разрешено использовать строковые шаблоны в случаях, когда необходима интерполяция

Числа

В числах запрещено опускать ноль в дробной и целой части

Запрещено использовать ведущий ноль при создании чисел, поскольку это приводит к созданию числа в восьмеричной системе счисления

Литералы

Массивы должны создаваться через литерал массива, а не через конструктор. Допустимое исключение — создание массива определенной длины

Объекты должны создаваться через литерал объекта, а не через конструктор

При создании объектов запрещено дублирование ключей

При описании функций запрещено дублировать названия параметров

В операторе switch запрещено дублировать условия (case)

Операторы

В бинарных и тернарных операторах операнды и символы оператора отделяются пробелами

Унарные операторы не отделяются от операнда пробелом. Исключения составляют операторы, состоящие из слов, а не символов, например оператор typeof

Именование

Все переменные должны быть названы в верблюжьем регистре (camelCase). Исключения составляют константы, которые должны именоваться прописными буквами в константном регистре (CONSTANT_CASE) и названия классов, функций-конструкторов и перечислений, которые именуются с заглавной буквы (PascalCase)

Запрещено использовать имена переменных, которые используются во внешних областях видимости

Запрещено называть переменные и свойства ключевыми словами JS

Запрещено использовать переменные, не объявленные ранее. При использовании переменной, объявленной в другом модуле в глобальной области видимости, нужно обращаться к ней как к свойству объекта window

Запрещено напрямую обращаться к значению undefined. Для проверки типа рекомендуется использовать typeof. Исключение составляет явная передача undefined при вызове функции вместо аргумента, чтобы использовать значение параметра по умолчанию

Предотвращение ошибок

Все точки с запятой должны быть проставлены явно, не стоит рассчитывать на автоматическую расстановку точек с запятой ASI (Automatic Semicolon Insertion)

Не рекомендуется использовать указатель Unicode BOM в коде, потому что код должен быть сохранен не в кодировке UTF-16, а в кодировке UTF-8, в которой нет указателя порядка бит

Обязательно используются блоки кода, даже если в выражении содержится одна строчка

В коде нет пустых блоков кода

Код работает в строгом режиме: в начале всех файлов явно прописана директива "use strict" или используются модули ECMAScript, которые по умолчанию работают в строгом режиме

Условные операторы

Запрещена «проверка Йоды» — в условных операторах в блоке условия при сравнении переменной или свойства со значением сначала идет переменная или свойство объекта и только потом значения, а не наоборот.

if (1 === myValue) { /*...*/ }
if (myValue === 1) { /*...*/ }

При сравнении двух значений используется оператор строгого сравнения вместо оператора нестрогого сравнения

В условных операторах не используется оператор присвоения

В условиях не используется небезопасное отрицание, например использование ! в in или instanceof без скобок

Запрещено сравнение с NaN. Для проверки, является ли результат операции числовым, нужно использовать Number.isNaN

Запрещено использовать case без break или return в блоках switch

Не используются вложенные тернарные операторы

Функции

Если в функции используется ветвление, в котором есть возврат значения, то return должен быть добавлен и в остальных ветках.

const doThings = function() {
  if (cond) {
    return 1;
  } else {
    doSomethingElse();
  }
};
const doThings = function() {
  if (cond) {
    return 1;
  } else {
    return doSomethingElse();
  }
};

Это правило предотвращает создание функций, при использовании которых непонятно, вернут ли они какое-то значение. В первом примере, функция do может вернуть значение 1, а может undefined

Единственное исключение — использование return без значения для прекращения работы функции:

const doThings = function() {
  if (cond) {
    doSomething()
    return;
  }

  doSomethingElse();
};

В return не используется оператор присваивания

В стрелочных функциях всегда используются скобки для параметров, даже если параметр один

Операторы

В конструкторе классов-наследников обязательно вызывается super()

В конструкторе нет обращения к this до того, как будет вызван super()

Объявление переменных и функций

При объявлении переменных предпочтение отдается ключевым словам let и const. Переменные объявляются через var только при наличии проблем с поддержкой ECMAScript 2015

Запрещено переопределять с помощью ключевого слова ранее созданные переменные

Запрещено использовать множественное объявление через одно ключевое слово. Для каждой переменной используется отдельный var, let или const.

const a = 1, b = 2;
const a = 1;
const b = 2;

Объявление функций

Запрещено переопределение функций, созданных с помощью функционального объявления (function declaration)

function myFunc() {};
myFunc = 2;

Новые функции не создаются с помощью конструктора Function

Вместо коллекции arguments, используется rest-оператор, если это позволяет версия языка

Для превращения массива с данными в аргументы вместо вызова функции через apply используется spread-оператор, если это позволяет версия языка

Math.max.apply(null, [1, 100, 15, 1000]);
Math.max(...[1, 100, 15, 1000]);

Создание значений

Не вызываются служебные конструкторы, создающие объекты из глобальной области видимости Math(), JSON(), Reflect()

При создании непустых массивов запрещено опускать пустые значения (ставить подряд несколько запятых)

Для создания новых значений не используются конструкторы примитивов String, Number, Boolean

Конструкторы вызываются со скобками, даже если у них нет параметров

Символы (Symbol) создаются вызовом функции Symbol без ключевого слова new

Хорошие практики

Не используется конструкция with

Не используются alert

Не используется выполнение кода через eval

Не используется неявный eval — в функциях, которые поддерживают передачу исполняемого кода как строку, например setTimeout

В ссылках используется протокол javascript:

Конструкторы не используются без ключевого слова new

В функциях не используются обращения к caller и callee

Манкипатчинг

Встроенные в язык объекты и прототипы не расширяются в рантайме

Не переопределяются глобальные значения (undefined, null, Object, window и прочие)

Контекст

bind не используется вне методов классов

В функциях, которые не являются методами никакого объекта или класса, не используется this

Переменные

Переменные, объявленные через var не удаляются оператором delete

Приведение типов

Не используется лишнее приведение к Boolean. Например, нет большого смысла переводить в boolean условия в конструкциях if, while, for, в первом операнде тернарного оператора

Оператор typeof используется корректно — используются только правильные значения, возвращаемые оператором, не производится сравнения со строковыми литералами, которые содержат некорректные значения typeof

В parseInt обязательно передается второй параметр — основание системы счисления, даже в случае с десятичной системой счисления

Константы в условиях

В блоки условия операторов if, while, for и тернарного оператора не передается константное значение, которое подразумевает, что условие выполняется (или не выполняется) всегда

if (true) {}
if (a > 1) {}
const ternaryValue = true ? 'a' : 'b';
const ternaryValue = isA() ? 'a' : 'b';

Чистый код

Лишние символы

Не используются лишние (множественные) точки с запятой

Отладчик и консоль

В коде не используются оставленные выводы в консоль

В коде нет забытых инструкций debugger

Неиспользуемый код

В проекте нет недоступного кода, который никогда не выполнится

if (false) {
  doSomething();
}
if (needToDoSomething()) {
  doSomething();
}

В коде нет объявленных, но неиспользуемых переменных

Обработка ошибок и исключения

Для выбрасывания исключения в оператор throw передаются только объекты Error. Передавать литералы запрещено.

throw 'Passed value is out of range';
throw new RangeError('Passed value is out of range');

В конструкции try..catch запрещен пустой блок catch

Прочее

При итерировании по объектам через for..in при работе со свойствами используется конструкция hasOwnProperty

В объектах напрямую не переопределяется свойство __iterator__

В объектах напрямую не переопределяется свойство __proto__. Разрешено переопределять __proto__ через Object.create или запись в прототип, объектов, созданных другими конструкторами, но напрямую редактировать __proto__ нельзя

const obj = {
  __proto__: Parent
};
const Obj = function() {};
Obj.prototype = new Parent();
const obj = new obj;

const obj = Object.create(Parent.prototype);

В коде не используются лейблы. Лейблы используются с конструкциями break и continue для направленного выхода из цикла и могут привести к слишком сложному для понимания коду

Блоки, использующиеся в коде, должны описывать тело функции, условия, оператора switch и прочие конструкции, относящиеся к группировке множественных операций. Блоки не должны использоваться сами по себе, любой блок должен быть частью другого выражения

В коде не используется оператор «запятая» для описания последовательностей действий. Для создания переменных используются отдельные ключевые слова let, const, var, операторы группировки, условные операторы и прочие конструкции. Исключение составляет начальное условие оператора for

const result = (1, 2); // 2
const result = 2;

switch (val = getVal(), val) {}
val = getVal();
switch(val) {}

for (let i = 0, l = 100; i < l; i++);

Регулярные выражения

В регулярных выражениях не используются «управляющие выражения»

В регулярных выражениях не используются пустые классы символов [] (блоки, ограниченные квадратными скобками)

В коде регулярные выражения не создаются через конструктор RegExp из строки, которая не может быть разобрана как правильное регулярное выражение

В регулярных выражениях не используются нескольких последовательных пробелов. Вместо этого предлагается использовать модификаторы количества

/   /.exec(myString);
/\s\s\s/.exec(myString);
/\s{3}/.exec(myString);