Стиль кода Академии HTML

github.com/htmlacademy/codeguide

Синтаксис

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

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

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

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

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

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

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

var name       = 1;
var longerName = 2;
var name = 1;
var longerName = 2;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

При объявлении анонимных функций, скобки с параметрами отделяются пробелом от ключевого слова function. Если функция именована, перед названием ставится пробел, после — нет

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

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

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

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

Строки

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

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

var foo = "Copyright \251";
var foo = "Copyright \u00A9";

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

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

Числа

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

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

Литералы

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

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

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

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

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

Операторы

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

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

Именование

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

Все переменные должны быть названы в верблюжьем регистре (camelCase). Исключения составляют константы которые должны именоваться прописными буквами в змеином регистре (UPPER_SNAKE_CASE)

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

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

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

Запрещено объявлять переменные без значения

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

С заглавной буквы называются только функции-конструкторы

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

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

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

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

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

Код работает в строгом режиме: в начале всех файлов явно прописана директива 'use strict'

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

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

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

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

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

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

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

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

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

Функции

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

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

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

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

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

Операторы

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

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

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

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

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

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

var a = 1, b = 2;
var a = 1;
var 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) {}
var ternaryValue = true ? 'a' : 'b';
var ternaryValue = isA() ? 'a' : 'b';

Чистый код

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

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

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

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

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

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

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

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

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

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

check === true && doSomething();
if (check) {
  doSomething();
}

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

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

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

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

Документирование

При написании jsDoc используются следующие ограничения:

необязательно добавлять текстовое описание конструкциям @return и @param, достаточно просто указания типа и названия параметра для @param

описание возвращаемного типа @return требуется только в том случае, если функция возвращает какое-то значение. Правило не действует для конструкторов, для них указывать @return необязательно. Также необязательно указывать тег @return для функций, в которых конструкция return используется без возвращаемого значения для выхода из функции

для описания возвращаемого значения из функции используется тег @return, а не @returns

Прочее

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

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

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

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

var 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 (var i = 0, l = 100; i < l; i++);

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

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

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

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

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

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

Node.js

В Node.js файлах не используется конструкция process.exit