- Объявление переменных
- Объекты
- Массивы
- Деструктуризация
- Строки
- Функции
- Стрелочные функции
- Итераторы и генераторы
- Переменные
- Операторы сравнения и равенства
- Блоки
- Точка с запятой
- События
- jQuery
Использование var
запрещено.
Если необходимо переопределять значения, то используйте let
. Если переменная не переопределяется, то используйте const
.
Для создания объекта используйте литеральную нотацию const item = {}
.
Используйте сокращённую запись метода объекта:
// Неудачная реализация
const atom = {
value: 1,
addValue: function (value) {
return atom.value + value;
},
};
// Удачная реализация
const atom = {
value: 1,
addValue(value) {
return atom.value + value;
},
};
Используйте сокращённую запись свойств объекта (в случае, когда наименование ключа совпадает с названием переменной):
const lukeSkywalker = 'Luke Skywalker';
const obj = {
lukeSkywalker,
};
Группируйте сокращённые записи свойств в начале объявления объекта. Так легче сказать, какие свойства используют сокращённую запись:
const anakinSkywalker = 'Anakin Skywalker';
const lukeSkywalker = 'Luke Skywalker'
const obj = {
lukeSkywalker,
anakinSkywalker,
episodeOne: 1,
twoJediWalkIntoACantina: 2,
episodeThree: 3,
mayTheFourth: 4,
};
Не вызывайте напрямую методы Object.prototype
, такие как hasOwnProperty
, propertyIsEnumerable
, и isPrototypeOf
. Эти методы могут быть переопределены в свойствах объекта, который мы проверяем { hasOwnProperty: false }
, или этот объект может быть null
(Object.create(null)
:
const has = Object.prototype.hasOwnProperty; // Кэшируем запрос в рамках модуля.
console.log(has.call(object, key))
Используйте оператор расширения вместо Object.assign
для поверхностного копирования объектов. Используйте синтаксис оставшихся свойств, чтобы получить новый объект с некоторыми опущенными свойствами:
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
Для создания массива используйте литеральную нотацию const items = []
.
Для добавления элемента в массив используйте Array.push
вместо прямого присваивания someStack.push('abracadabra')
.
const someStack = [];
// Неудачная реализация
someStack[someStack.length] = 'abracadabra';
// Удачная реализация
someStack.push('abracadabra');
Для копирования массивов используйте оператор расширения ...
: const itemsCopy = [...items]
Для преобразования итерируемого объекта в массив используйте оператор расширения ...
вместо Array.from
: const nodes = [...foo]
.
Используйте операторы return
внутри функций обратного вызова в методах массива. Можно опустить return
, когда тело функции состоит из одной инструкции, возвращающей выражение без побочных эффектов:
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
[1, 2, 3].map((x) => x + 1);
[[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
const flatten = acc.concat(item);
return flatten;
});
// хорошо
inbox.filter((msg) => {
const { subject, author } = msg;
if (subject === 'Mockingbird') {
return author === 'Harper Lee';
}
return false;
});
При обращении к нескольким свойствам объекта используйте деструктуризацию объекта. Деструктуризация избавляет вас от создания временных переменных для этих свойств.
// В случае необходимости использовать другие ключи user
function getFullName(user) {
const { firstName, lastName } = user;
return `${firstName} ${lastName}`;
}
// При использовании конкретных ключей user
function getFullName({ firstName, lastName }) {
return `${firstName} ${lastName}`;
}
Используйте деструктуризацию массивов:
const arr = [1, 2, 3, 4];
// Неудачная реализация
const first = arr[0];
const second = arr[1];
// Удачная реализация
const [first, second] = arr;
Используйте деструктуризацию объекта для множества возвращаемых значений, но не делайте тоже самое с массивами. Вы сможете добавить новые свойства через некоторое время или изменить порядок без последствий:
// Неудачная реализация
function processInput(input) {
// затем происходит чудо
return [left, right, top, bottom];
}
// при вызове нужно подумать о порядке возвращаемых данных
const [left, __, top] = processInput(input);
// Удачная реализация
function processInput(input) {
// затем происходит чудо
return { left, right, top, bottom };
}
// при вызове выбираем только необходимые данные
const { left, top } = processInput(input);
Используйте одинарные кавычки ''
для строк.
Если есть необходимость встроить значение переменной в строку, то используйте шаблонный вариант: const question = `How are you, ${name}?`
Используйте функциональные выражения без наименования функции после function
вместо объявлений функций:
const foo = function () {
// ...
};
Оборачивайте в скобки немедленно вызываемые функции. Немедленно вызываемая функция представляет собой единый блок. Чтобы чётко показать это — оберните функцию и вызывающие скобки в ещё одни скобки. Обратите внимание, что в мире с модулями вам больше не нужны немедленно вызываемые функции.
(function () {
console.log('Welcome to the Internet. Please follow me.');
}());
Используйте синтаксис записи аргументов по умолчанию, а не изменяйте аргументы функции.
Вместо отсутствующего скалярного значения используется null. 0 и пустую строку нельзя использовать в качестве показателя отсутствия значения:
function sendEmail(title, message = null, date = null) {
// ...
}
// сообщение не было передано
obj.sendEmail('Title', null, '2017-01-01');
// было передано пустое сообщение
obj.sendEmail('Title', '', '2017-01-01');
Отдельные скрипты с логикой под конкретный компонент/модуль/раздел/секцию/ и т.д. должен быть либо в классах и экспортом из ES6, либо в самовызываюшейся функции, чтобы был в локальной области действия, а не глобальной.
Когда вам необходимо использовать анонимную функцию (например, при передаче встроенной функции обратного вызова), используйте стрелочную функцию. Таким образом создаётся функция, которая выполняется в контексте this
, который мы обычно хотим, а также это более короткий синтаксис. Если у вас есть довольно сложная функция, вы можете переместить эту логику внутрь её собственного именованного функционального выражения.
// Неудачная реализация
[1, 2, 3].map(function (x) {
const y = x + 1;
return x * y;
});
// Удачная реализация
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
[1, 2, 3].map((x) => x * x);
Если тело функции состоит из одного оператора, возвращающего выражение без побочных эффектов, то опустите фигурные скобки и используйте неявное возвращение. В противном случае, сохраните фигурные скобки и используйте оператор return
. Синтаксический сахар. Когда несколько функций соединены вместе, то это лучше читается.
// Неудачная реализация
[1, 2, 3].map((number) => {
const nextNumber = number + 1;
`A string containing the ${nextNumber}.`;
});
// Удачная реализация
[1, 2, 3].map((number) => `A string containing the ${number + 1}.`);
// Удачная реализация
[1, 2, 3].map((number) => {
const nextNumber = number + 1;
return `A string containing the ${nextNumber}.`;
});
// Удачная реализация
[1, 2, 3].map((number, index) => ({
[index]: number,
}));
// Неявный возврат с побочными эффектами
function foo(callback) {
const val = callback();
if (val === true) {
// Сделать что-то, если функция обратного вызова вернёт true
}
}
let bool = false;
// Неудачная реализация
foo(() => bool = true);
// Удачная реализация
foo(() => {
bool = true;
});
Всегда оборачивайте аргументы круглыми скобками для ясности и согласованности. Минимизирует различия при удалении или добавлении аргументов.
// Удачная реализация
[1, 2, 3].map((x) => x * x);
// Удачная реализация
[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!`
));
// Удачная реализация
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
Не используйте итераторы. Применяйте функции высшего порядка вместо таких циклов как for-in
или for-of
. Это обеспечивает соблюдение нашего правила о неизменности переменных. Работать с чистыми функциями, которые возвращают значение, проще, чем с функциями с побочными эффектами. Используйте map()
/ every()
/ filter()
/ find()
/ findIndex()
/ reduce()
/ some()
/ ... для итерации по массивам, а Object.keys()
/ Object.values()
/ Object.entries()
для создания массивов, с помощью которых можно итерироваться по объектам.
const numbers = [1, 2, 3, 4, 5];
// Неудачная реализация
const increasedByOne = [];
for (let i = 0; i < numbers.length; i++) {
increasedByOne.push(numbers[i] + 1);
}
// Удачная реализация
const increasedByOne = [];
numbers.forEach((num) => {
increasedByOne.push(num + 1);
});
// Удачная реализация
const increasedByOne = numbers.map((num) => num + 1);
Используйте объявление const
или let
для каждой переменной или присвоения. Таким образом проще добавить новые переменные. Также вы никогда не будете беспокоиться о перемещении ;
и ,
и об отображении изменений в пунктуации. Вы также можете пройтись по каждому объявлению с помощью отладчика, вместо того, чтобы прыгать через все сразу.
// Неудачная реализация
const items = getItems(),
goSportsTeam = true,
dragonball = 'z';
// Удачная реализация
const items = getItems();
const goSportsTeam = true;
const dragonball = 'z';
В первую очередь группируйте const
, а затем let
. Это полезно, когда в будущем вам понадобится создать переменную, зависимую от предыдущих.
Если константа хранит объект событий, то сама переменная именуются с заглавной буквы (как в предложении), а ключи объекта заглавыми буквами с разделением слов с помощью символа _ (нижнее подчеркивание):
const Event = {
CLICK : ...,
DRAG : ...
}
Event.CLICK
Если константа хранит объект селекторов или других значений, то она именуются с заглавной буквы (как в предложении) и каждое слово начинается с заглавной буквы, а ключи объекта стилем camelCase
.
Комбинирование стилей допустимо:
const Selector = {
submitButton : $(...),
CLICK : anyClick(),
}
Запрещается использовать магические строки и числа. Все должно быть определено заранее, например в виде констант:
// Плохо
if (status === 'failed') ...
if (myVarType === 'elementTypeConnection') ...
// Хорошо
const DOC_STATUS_FAILED = 'failed';
const EQUIPMENT_TYPE_CONNECTION = 'connection';
if (state === DOC_STATUS_FAILED) ...
if (myVarType === EQUIPMENT_TYPE_CONNECTION) ..
Для модуля/компонента и в целом имеет смысл заранее объявлять список селекторов и имен идентификаторов, к которым будут обращаться в низлежащем коде.
// Плохо
$(document).on('click', '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top', function() {
// ...
});
// Хорошо
const Selector = {
dialog : '.modal-dialog',
dataDismiss : '[data-dismiss="modal"]',
fixedContent : '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top',
}
$(document).on('click', Selector.fixedContent, function() {
// ...
});
Переменные let, которые хранят в себе селектор необходимо объявлять в случае, если подразумевается неоднократное использование. В других случаях лучше использовать константу селекторов.
Используйте ===
и !==
вместо ==
и !=
.
Используйте сокращения для булевских типов, а для строк и чисел применяйте явное сравнение.
// Неудачная реализация
if (isValid === true) {
// ...
}
// Удачная реализация
if (isValid) {
// ...
}
// Неудачная реализация
if (name) {
// ...
}
// Удачная реализация
if (name !== '') {
// ...
}
// Неудачная реализация
if (collection.length) {
// ...
}
// Удачная реализация
if (collection.length > 0) {
// ...
}
Тернарные операторы не должны быть вложены и в большинстве случаев должны быть расположены на одной строке.
// Неудачная реализация
const foo = maybe1 > maybe2
? "bar"
: value1 > value2 ? "baz" : null;
// Удачная реализация
const maybeNull = value1 > value2 ? 'baz' : null;
const foo = maybe1 > maybe2
? 'bar'
: maybeNull;
// Удачная реализация
const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
Используйте фигурные скобки всегда.
// Неудачная реализация
if (test) return false;
// Неудачная реализация
if (test)
return false;
// Неудачная реализация
function foo() { return false; }
// Удачная реализация
function bar() {
return false;
}
Если в блоке if
всегда выполняется оператор return
, последующий блок else
не нужен. return
внутри блока else if
, следующем за блоком if
, который содержит return
, может быть разделён на несколько блоков if
.
// Неудачная реализация
function foo() {
if (x) {
return x;
} else {
return y;
}
}
// Неудачная реализация
function cats() {
if (x) {
return x;
} else if (y) {
return y;
}
}
// Неудачная реализация
function dogs() {
if (x) {
return x;
} else {
if (y) {
return y;
}
}
}
// Удачная реализация
function foo() {
if (x) {
return x;
}
return y;
}
// Удачная реализация
function cats() {
if (x) {
return x;
}
if (y) {
return y;
}
}
// Удачная реализация
function dogs(x) {
if (x) {
if (z) {
return y;
}
} else {
return z;
}
}
Точка с запятой ;
ставится обязательно везде.
Когда привязываете данные к событию (например, события DOM
или какие-то собственные события, как Backbone
события), передавайте литерал объекта (также известный как «хэш») вместо простого значения. Это позволяет другим разработчикам добавлять больше данных без поиска и изменения каждого обработчика события. В качеству аргумента события используйте слово event
вместо e
. К примеру, вместо:
// Неудачная реализация
$(this).trigger('listingUpdated', listing.id);
// ...
$(this).on('listingUpdated', (event, listingID) => {
// делает что-то с listingID
});
предпочитайте:
// Удачная реализация
$(this).trigger('listingUpdated', { listingID: listing.id });
// ...
$(this).on('listingUpdated', (event, data) => {
// делает что-то с data.listingID
});
Начинайте названия переменных, хранящих объект jQuery, со знака $
.
// Неудачная реализация
const sidebar = $('.sidebar');
// Удачная реализация
const $sidebar = $('.sidebar');
// Удачная реализация
const $sidebarBtn = $('.sidebar-btn');
Кэшируйте jQuery-поиски.
// Неудачная реализация
function setSidebar() {
$('.sidebar').hide();
// ...
$('.sidebar').css({
'background-color': 'pink',
});
}
// Удачная реализация
function setSidebar() {
const $sidebar = $('.sidebar');
$sidebar.hide();
// ...
$sidebar.css({
'background-color': 'pink',
});
}
Для поиска в DOM используйте каскады $('.sidebar ul')
или селектор родитель > ребёнок $('.sidebar > ul')
.
Используйте функцию find
для поиска в сохранённых jQuery-объектах.
// Неудачная реализация
$('ul', '.sidebar').hide();
// плохо
$('.sidebar').find('ul').hide();
// Удачная реализация
$('.sidebar ul').hide();
// Удачная реализация
$('.sidebar > ul').hide();
// Удачная реализация
$sidebar.find('ul').hide();