JavaScript настолько гибкий язык программирования, что дает вам возможность достигать целей разными способами. При этом существует ряд принципов и рекомендаций, соблюдение которых позволит улучшить читаемость и производительность кода.
1. Пишите код в стиле строго типизированного языка
JavaScript — слабо типизированный язык, в котором переменная синтаксически может иметь разные типы значений. Но в целях повышения производительности компиляции и обеспечения лучшей читаемости рекомендуется писать код в строго типизированном стиле.
Конкретизируйте тип данных при определении переменной
Плохой код:

В данном примере переменные не содержат информацию о типе, что усложняет понимание кода или его оптимизацию интерпретатором JavaScript.
Хороший код:

Не меняйте тип переменной произвольно
Плохой код:

Изначально earning
является целым числом, а затем становится строкой. Если кто-то решит прочитать или даже изменить такой код, то у него неизбежно возникнут сомнения, за которыми могут последовать и ошибки.
В то же время в движках типа V8 код JavaScript выполняется после того, как преобразуется в байт-код, в котором тип данных определен. В случае изменения типа переменной компилятору придется заняться дополнительной обработкой, что замедлит выполнение программы.
Хороший код:

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

Данная функция может вернуть целое число или строку. Это не противоречит синтаксису JavaScript, но затрудняет вызов функции для выполнения арифметических действий непосредственно с результатом getPrice()
.
Хороший код:

В комментарии к функции мы можем условиться, что в случае возврата -1
аргумент является некорректным. Это позволит вызывающему компоненту обработать результат стандартным способом.
2. Сокращайте число необязательных просмотров областей видимости
JavaScript поддерживает вложенные области видимости и их цепочки, что способствует написанию эффективного кода. Однако неправильное применение данного синтаксиса приводит к ошибкам.
Не раскрывайте код для глобальной области видимости без необходимости
Плохой код:

Во-первых, все переменные в теге script находятся в глобальной области видимости. При этом код в разных тегах script могут писать разные программисты, в связи с чем появляется вероятность конфликтов имен.
Во-вторых, при использовании переменной element
вторая строка кода ищет эту переменную в глобальной области, тем самым снижая быстродействие программы.
Хороший код:

В этом примере с помощью замыканий мы скрываем переменную element
, что позволяет не только не засорять глобальную область, но и быстрее находить переменные в локальной.
Но если вы планируете применять переменную element
в других частях кода, то ее все же следует объявить в глобальной области видимости.
Не злоупотребляйте замыканиями
В JavaScript поиск переменных осуществляется с помощью цепочки областей видимости. Если переменная не обнаружена в текущей области, то движок продолжает ее искать в родительской, последовательно переходя все выше и заканчивая путь в глобальной области. Чем глубже уровень вложенности замыкания, тем дольше поиск переменной.
Плохой код:

Переменная count
в верхней части области используется внутри функции process
, вследствие чего при ее вызове движок JavaScript тратит больше времени на поиск этой переменной.
В то же время, если область углублена на несколько уровней, а между process
иcount
располагаются десятки строк кода, то при считывании функции process переменную count легко перепутать.
Вот поэтому будет лучше передать count
в качестве параметра process
.
Хороший код:

3. Используйте возможности ES6 для упрощения кода
ES6 существует уже несколько лет и на данный момент широко совместимым. Активное применение его потенциала позволит создавать более лаконичный и понятный код.
Реализуйте обратные вызовы стрелочными функциями, а не обычными
Если вам не нужно задумываться о привязке this
, то в качестве функций обратного вызова лучше задействовать стрелочные вместо обычных.
Плохой код:

Хороший код:

Класс
Традиционный синтаксис прототипа отделит код конструктора от кода метода прототипа, препятствуя эффективной организации кода.
Плохой код:

Благодаря применению класса упрощается как понимание кода, так и реализация наследуемых статических функций-членов.
Хороший код:

Шаблонные строки
Шаблонные строки заключены в обратные кавычки (` `
) вместо двойных или одинарных.
Плохой код:

В шаблонных строках допустимы любые символы вместо escape-символов, таких как \n
.
В то же время мы можем напрямую использовать выражение ${}
для вставки переменных вместо разделения строк и конкатенации с помощью +
.
Хороший код:

Очевидно, что данный код читается легче.
Параметры по умолчанию
Когда нужно присвоить аргументам функции значение по умолчанию, в ES5 можно написать следующий код:

В ES6 используется уже более понятный и читаемый способ.

Переменные с блочной областью видимости
Для последовательного вывода в консоль чисел 0, 1, 2, …10 с интервалом в 100 мс возможен следующий вариант кода:
for(var index = 0; index <= 10; index++){
setTimeout(() => console.log(index), 100)
}
К сожалению, этот код не соответствует требованиям. Так как объявленные с помощью var
переменные находятся в глобальной области видимости, значение index
меняется на 11 при выполнении функции обратного вызова setTimeout.

В ES5 предлагается решение в виде замыканий:
for(var index = 0; index <= 10; index++){
(function(archivedIndex){
setTimeout(() => console.log(archivedIndex), 100)
})(index)
}

В данном примере мы сохраняем значение index
с помощью замыкания, чтобы при выполнении setTimeout обнаруживалось верное значение index.
Но этот вариант трудоёмкий и сложный для понимания. Намного лучше с помощью let
объявить переменную с блочной областью видимости.
for(let index = 0; index <= 10; index++){
setTimeout(() => console.log(index), 100)
}

Для завершения условия нужно изменить лишь три символа, сделав его простым, удобным и читаемым.
4. Грамматический стиль
Замените простую условную конструкцию if-else на тернарный оператор
В целом синтаксис тернарного оператора выглядит так:
condition ? expression_1 : expression_2;
condition
— это выражение, которое вычисляется в логическое значение true
или false
. Если его условие равно true
, то тернарный оператор возвращает expression_1
, в противном случае — expression_2
.
Плохой код:

Хороший код:

Избегайте ==
Оператор ==
подразумевает множество механизмов, поэтому чрезмерное его применение усложнит понимание кода, который можно сделать понятнее путем явного преобразования типов данных.
Плохой код:

Хороший код:

Читайте также:
- Три точки (…) в Javascript
- Паттерн проектирования «Наблюдатель»: объект под прицелом
- 5 основных рекурсивных задач на собеседованиях по программированию
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи bitfish: 4 Key Principles to Writing Readable and Efficient JavaScript Code