Skip to content

Latest commit

 

History

History
664 lines (501 loc) · 23.3 KB

javascript.md

File metadata and controls

664 lines (501 loc) · 23.3 KB

Содержание

  1. Объявление переменных
  2. Объекты
  3. Массивы
  4. Деструктуризация
  5. Строки
  6. Функции
  7. Стрелочные функции
  8. Итераторы и генераторы
  9. Переменные
    1. Константы
    2. Селекторы
  10. Операторы сравнения и равенства
  11. Блоки
  12. Точка с запятой
  13. События
  14. 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

Начинайте названия переменных, хранящих объект 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();