ES6 Style Guide - Lebedancer/component-example GitHub Wiki

Оглавление

  1. Типы
  2. Ссылки
  3. Объекты
  4. Массивы
  5. Destructuring
  6. Строки
  7. Функции
  8. Arrow Functions
  9. Классы
  10. Модули
  11. Итераторы и генераторы
  12. Свойства
  13. Переменные
  14. Область видимости и "поднятие"
  15. Операторы сравнения и равенство
  16. Блоки кода
  17. Комментарии
  18. Пробелы
  19. Запятые
  20. Точки с запятой
  21. Приведение типов
  22. Соглашения об именовании
  23. Функции доступа get и set
  24. События
  25. jQuery
  26. Совместимость с ES5
  27. Стили ECMAScript 6
  28. Тестирование
  29. Быстродействие
  30. Ресурсы
  31. Лицензия

Типы

  • 1.1 Простые типы: Когда вы взаимодействуете с простым типом, вы работаете непосредственно с его значением

    • string
    • number
    • boolean
    • null
    • undefined
    const foo = 1;
    let bar = foo;
    
    bar = 9;
    
    console.log(foo, bar); // => 1, 9
    
  • 1.2 Сложные типы: Когда вы взаимодействуете со сложным типом, вы работаете со ссылкой на его значение.

    • object
    • array
    • function
    const foo = [1, 2];
    const bar = foo;
    
    bar[0] = 9;
    
    console.log(foo[0], bar[0]); // => 9, 9
    

References

  • 2.1 Используйте const для всех ссылок на значения; избегайте использования var.

Почему? Чтобы быть уверенными, что нельзя будет присвоить переменной новое значение (mutation), что может привести к ошибкам и сложности понимания кода.

```javascript
// плохо
var a = 1;
var b = 2;

// хорошо
const a = 1;
const b = 2;
```
  • 2.2 Если вам необходимо изменить ссылку, используйте let вместо var.

Почему? Область видимости let ограничена блоком, тогда как var - функцией.

```javascript
// плохо
var count = 1;
if (true) {
  count += 1;
}

// хорошо, use the let.
let count = 1;
if (true) {
  count += 1;
}
```
  • 2.3 Заметьте, что и для let, и для const` областью видимости является блок.

    // const и let существуют только внутри блока, где они объявлены.
    {
      let a = 1;
      const b = 1;
    }
    console.log(a); // ReferenceError
    console.log(b); // ReferenceError
    

Объекты

  • 3.1 Для создания объекта используйте фигурные скобки

    // плохо
    const item = new Object();
    
    // хорошо
    const item = {};
    
  • 3.2 Не используйте зарезервированные слова в качестве ключей объекта (если ваш код будет выполняться браузером в качестве скрипта). Это не будет работать в IE8. Подробнее. Зарезервированные слова можно использовать в модулях ES6 и на сервере.

    // плохо
    const superman = {
      default: { clark: 'kent' },
      private: true,
    };
    
    // хорошо
    const superman = {
      defaults: { clark: 'kent' },
      hidden: true,
    };
    
  • 3.3 Используйте синонимы вместо зарезервированных слов

    // плохо
    const superman = {
      class: 'alien',
    };
    
    // плохо
    const superman = {
      klass: 'alien',
    };
    
    // хорошо
    const superman = {
      type: 'alien',
    };
    

  • 3.4 Используйте программно-созданные имена при создании объектов.

Почему? Это позволяет объявить все свойства объекта в одном месте.

```javascript

function getKey(k) {
  return `a key named ${k}`;
}

// плохо
const obj = {
  id: 5,
  name: 'San Francisco',
};
obj[getKey('enabled')] = true;

// хорошо
const obj = {
  id: 5,
  name: 'San Francisco',
  [getKey('enabled')]: true,
};
```

  • 3.5 Используйте короткую запись при объявлении методов объекта.

    // плохо
    const atom = {
      value: 1,
    
      addValue: function (value) {
        return atom.value + value;
      },
    };
    
    // хорошо
    const atom = {
      value: 1,
    
      addValue(value) {
        return atom.value + value;
      },
    };
    

  • 3.6 Используйте короткую запись при объявлении свойств объекта.

Почему? Короче писать.

```javascript
const lukeSkywalker = 'Luke Skywalker';

// плохо
const obj = {
  lukeSkywalker: lukeSkywalker,
};

// хорошо
const obj = {
  lukeSkywalker,
};
```
  • 3.7 Располагайте свойства, для которых использована короткая запись, в начале объекта при его объявлении.

Почему? Так проще показать, для каких свойств используется короткая запись.

```javascript
const anakinSkywalker = 'Anakin Skywalker';
const lukeSkywalker = 'Luke Skywalker';

// плохо
const obj = {
  episodeOne: 1,
  twoJediWalkIntoACantina: 2,
  lukeSkywalker,
  episodeThree: 3,
  mayTheFourth: 4,
  anakinSkywalker,
};

// хорошо
const obj = {
  lukeSkywalker,
  anakinSkywalker,
  episodeOne: 1,
  twoJediWalkIntoACantina: 2,
  episodeThree: 3,
  mayTheFourth: 4,
};
```

Массивы

  • 4.1 Используйте квадратные скобки для создания массива

    // плохо
    const items = new Array();
    
    // хорошо
    const items = [];
    
  • 4.2 Используйте Array#push вместо присваивания напрямую чтобы добавить элементы в массив.

    const someStack = [];
    
    // плохо
    someStack[someStack.length] = 'abracadabra';
    
    // хорошо
    someStack.push('abracadabra');
    

  • 4.3 Используйте оператор ... чтобы скопировать массив.

    // плохо
    const len = items.length;
    const itemsCopy = [];
    let i;
    
    for (i = 0; i < len; i++) {
      itemsCopy[i] = items[i];
    }
    
    // хорошо
    const itemsCopy = [...items];
    
  • 4.4 Чтобы создать из похожего на массив объекта массив, используйте Array#from.

    const foo = document.querySelectorAll('.foo');
    const nodes = Array.from(foo);
    

Destructuring

  • 5.1 Используйте destructuring для доступа к свойствам объекта.

Почему? Это избавляет вас от создания временных ссылок на нужные свойства.

```javascript
// плохо
function getFullName(user) {
  const firstName = user.firstName;
  const lastName = user.lastName;

  return `${firstName} ${lastName}`;
}

// хорошо
function getFullName(obj) {
  const { firstName, lastName } = obj;
  return `${firstName} ${lastName}`;
}

// лучший способ
function getFullName({ firstName, lastName }) {
  return `${firstName} ${lastName}`;
}
```
  • 5.2 Используйте array destructuring.

    const arr = [1, 2, 3, 4];
    
    // плохо
    const first = arr[0];
    const second = arr[1];
    
    // хорошо
    const [first, second] = arr;
    
  • 5.3 Используйте object destructuring вместо array destructuring, если функция возвращает несколько значений.

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

```javascript
// плохо
function processInput(input) {
  // then a miracle occurs
  return [left, right, top, bottom];
}

// необходимо знать порядок возвращаемых данных
const [left, __, top] = processInput(input);

// хорошо
function processInput(input) {
  // then a miracle occurs
  return { left, right, top, bottom };
}

// при вызове просто используются нужные данные
const { left, right } = processInput(input);
```

Строки

  • 6.1 Используйте одинарные кавычки '' для строк

    // плохо
    const name = "Capt. Janeway";
    
    // хорошо
    const name = 'Capt. Janeway';
    
  • 6.2 Строки длиннее 100 символов нужно разделять, выполняя перенос через конкатенацию строк.

  • 6.3 Примечание: строки с большим количеством конкатенаций могут отрицательно влиять на быстродействие. jsPerf и обсуждение

    // плохо
    const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';
    
    // плохо
    const errorMessage = 'This is a super long error that was thrown because \
    of Batman. When you stop to think about how Batman had anything to do \
    with this, you would get nowhere \
    fast.';
    
    // хорошо
    const errorMessage = 'This is a super long error that was thrown because ' +
      'of Batman. When you stop to think about how Batman had anything to do ' +
      'with this, you would get nowhere fast.';
    

  • 6.4 Когда строка создается программным путем, используйте шаблон вместо объединения строк.

Почему? Шаблоны дают вам читаемый, лаконичный синтаксис с функцией вставки в строку.

```javascript
// плохо
function sayHi(name) {
  return 'How are you, ' + name + '?';
}

// плохо
function sayHi(name) {
  return ['How are you, ', name, '?'].join();
}

// хорошо
function sayHi(name) {
  return `How are you, ${name}?`;
}
```
  • 6.5 Никогда не используйте eval() на строках, это порождает много уязвимостей.

Функции

  • 7.1 Используйте function declarations вместо function expressions.

Почему? Function declarations именованные, поэтому функции проще отследить в call stack'е. Так же все тело функции function declaration поднимается к началу области видимости, тогда как при использовании function expression поднимается только ссылка. Это правило позволяет всегда использовать Arrow Functions вместо function expressions.

```javascript
// плохо
const foo = function () {
};

// хорошо
function foo() {
}
```
  • 7.2 Function expressions:

    // объявление функции, которая сразу же выполняется (IIFE)
    (() => {
      console.log('Welcome to the Internet. Please follow me.');
    })();
    
  • 7.3 Никогда не объявляйте функцию внутри блока кода - не функции (if, while, else и т.д.). Вместо этого присваивайте функцию уже объявленной переменной. Это будет работать, но в различных браузерах по-разному.

  • 7.4 Note: ECMA-262 устанавливает понятие блока как списка операторов. Function declaration не является оператором. Комментарий по этому вопросу в ECMA-262.

    // плохо
    if (currentUser) {
      function test() {
        console.log('Nope.');
      }
    }
    
    // хорошо
    let test;
    if (currentUser) {
      test = () => {
        console.log('Yup.');
      };
    }
    
  • 7.5 Никогда не называйте параметр функции arguments, он будет более приоритетным над объектом arguments, который доступен для каждой функции.

    // плохо
    function nope(name, options, arguments) {
      // ...код...
    }
    
    // хорошо
    function yup(name, options, args) {
      // ...код...
    }
    

  • 7.6 Никогда не используйте arguments, вместо этого лучше использовать остаточный параметр ....

Почему? ... явно показывает, какие аргументы вы хотите объединить в pull. Более того, остаточные параметр - действительно массив, в отличие от arguments.

```javascript
// плохо
function concatenateAll() {
  const args = Array.prototype.slice.call(arguments);
  return args.join('');
}

// хорошо
function concatenateAll(...args) {
  return args.join('');
}
```

  • 7.7 Предпочтительнее использовать параметры по умолчанию, чем изменяемые аргументы функции.

    // действительно плохо
    function handleThings(opts) {
      // Нет! Мы не должны изменять аргументы функции.
      // Вдвойне плохо: если opts приводится к false, ему будет присвоен объект,
      // что, возможно, именно то, что вы хотите, но что может привести к трудно находимым ошибкам
      opts = opts || {};
      // ...
    }
    
    // все еще плохо
    function handleThings(opts) {
      if (opts === void 0) {
        opts = {};
      }
      // ...
    }
    
    // хорошо
    function handleThings(opts = {}) {
      // ...
    }
    
  • 7.8 Избегайте побочных эффектов параметров по умолчанию.

var b = 1;
// плохо
function count(a = b++) {
  console.log(a);
}
count();  // 1
count();  // 2
count(3); // 3
count();  // 3
  • 7.9 Всегда описывайте параметры по умолчанию последними.

    // плохо
    function handleThings(opts = {}, name) {
      // ...
    }
    
    // хорошо
    function handleThings(name, opts = {}) {
      // ...
    }
    
  • 7.10 Никогда не используйте конструктор Function для создания новой функции.

    Почему? Создание функции таким способом Creating a function выполняет строку, как eval(), что открывает уязвимости.

    // плохо
    var add = new Function('a', 'b', 'return a + b');
    
    // все еще плохо
    var subtract = Function('a', 'b', 'return a - b');
    

Arrow Functions

  • 8.1 Когда вам необходимо использовать function expressions (например объявить анонимную функцию), используйте arrow function.

Почему? Так создается версия функции, которая выполняется в контексте this, и запись короче.

Почему нет? Если у вас очень сложная функция, вы можете вынести логику в function declaration.

```javascript
// плохо
[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;
});
```
  • 8.2 Если тело функции состоит из одного выражения, можно опустить фигурные скобки и использовать скрытый return. В других случаях используйте return.

Почему? Синтаксический сахар. Читается легко, когда несколько функций вызываются в цепочке.

Почему нет? Если вы собираетесь возвращать объект.

```javascript
// хорошо
[1, 2, 3].map(number => `A string containing the ${number}.`);

// плохо
[1, 2, 3].map(number => {
  const nextNumber = number + 1;
  `A string containing the ${nextNumber}.`;
});

// хорошо
[1, 2, 3].map(number => {
  const nextNumber = number + 1;
  return `A string containing the ${nextNumber}.`;
});
```
  • 8.3 В случае, если выражение занимает несколько строк, заключите его в скобки для лучшей читаемости.

Почему? Так понятнее, где функция начинается и кончается.

```javascript
// плохо
[1, 2, 3].map(number => 'As time went by, the string containing the ' +
  `${number} became much longer. So we needed to break it over multiple ` +
  'lines.'
);

// хорошо
[1, 2, 3].map(number => (
  `As time went by, the string containing the ${number} became much ` +
  'longer. So we needed to break it over multiple lines.'
));
```
  • 8.4 Если функция принимает только один аргумент, можете опустить скобки.

Почему? Меньше визуальных помех.

```js
// хорошо
[1, 2, 3].map(x => x * x);

// хорошо
[1, 2, 3].reduce((y, x) => x + y);
```

Классы

  • 9.1 Всегда используйте class. Избегайте работы с prototype напрямую.

Почему? Синтаксис class более краток и понятен.

```javascript
// плохо
function Queue(contents = []) {
  this._queue = [...contents];
}
Queue.prototype.pop = function() {
  const value = this._queue[0];
  this._queue.splice(0, 1);
  return value;
}


// хорошо
class Queue {
  constructor(contents = []) {
    this._queue = [...contents];
  }
  pop() {
    const value = this._queue[0];
    this._queue.splice(0, 1);
    return value;
  }
}
```
  • 9.2 Используйте extends для наследования.

Почему? Это встроенный способ для наследования функционала прототипа, не ломающий логику instanceof.

```javascript
// плохо
const inherits = require('inherits');
function PeekableQueue(contents) {
  Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function() {
  return this._queue[0];
}

// хорошо
class PeekableQueue extends Queue {
  peek() {
    return this._queue[0];
  }
}
```
  • 9.3 Методы могут возвращать this для создания цепочек вызовов.

    // плохо
    Jedi.prototype.jump = function() {
      this.jumping = true;
      return true;
    };
    
    Jedi.prototype.setHeight = function(height) {
      this.height = height;
    };
    
    const luke = new Jedi();
    luke.jump(); // => true
    luke.setHeight(20); // => undefined
    
    // хорошо
    class Jedi {
      jump() {
        this.jumping = true;
        return this;
      }
    
      setHeight(height) {
        this.height = height;
        return this;
      }
    }
    
    const luke = new Jedi();
    
    luke.jump()
      .setHeight(20);
    
  • 9.4 Вы можете заменить стандартный метод toString(), но убедитесь, что он работает и не вызывает побочных эффектов.

    class Jedi {
      constructor(options = {}) {
        this.name = options.name || 'no name';
      }
    
      getName() {
        return this.name;
      }
    
      toString() {
        return `Jedi - ${this.getName()}`;
      }
    }
    

Модули

  • 10.1 Всегда используйте модули (import/export) вместо нестандартной модульной системы. Вы всегда можете собрать код в предпочитаемую модульную систему.

    // плохо
    const AirbnbStyleGuide = require('./AirbnbStyleGuide');
    module.exports = AirbnbStyleGuide.es6;
    
    // нормально
    import AirbnbStyleGuide from './AirbnbStyleGuide';
    export default AirbnbStyleGuide.es6;
    
    // лучший вариант
    import { es6 } from './AirbnbStyleGuide';
    export default es6;
    
  • 10.2 Не используйте группировку при импорте.

Почему? Чтобы быть уверенными, что экспортируется один объект.

```javascript
// плохо
import * as AirbnbStyleGuide from './AirbnbStyleGuide';

// хорошо
import AirbnbStyleGuide from './AirbnbStyleGuide';
```
  • 10.3 Не экспортируйте прямо из импорта.

Почему? Хотя одна строка и выглядит лаконично, чистый импорт и затем чистый экспорт выглядят более последовательно.

```javascript
// плохо
// filename es6.js
export { es6 as default } from './airbnbStyleGuide';

// хорошо
// filename es6.js
import { es6 } from './AirbnbStyleGuide';
export default es6;
```
  • 10.4 Размещайте все импорты в начале файла.

    // плохо
    

import mdCore from 'mdCore'; ....your code import template from 'template.html';

// хорошо
import mdCore from 'mdCore';
import template from 'template.html';
  ....your code

```

Итераторы и генераторы

  • 11.1 Не используйте итераторы. Предпочтительнее использовать функции, такие как map() и reduce() вместо циклов вроде for-of.

Почему? Это обеспечивает правило неизменяемости. При работе с функциями проще обсуждать побочные эффекты.

```javascript
const numbers = [1, 2, 3, 4, 5];

// плохо
let sum = 0;
for (let num of numbers) {
  sum += num;
}

sum === 15;

// хорошо
let sum = 0;
numbers.forEach((num) => sum += num);
sum === 15;

// лучший вариант 
const sum = numbers.reduce((total, num) => total + num, 0);
sum === 15;
```
  • 11.2 Не используйте генераторы.

Почему? Они не компилируются корректно в ES5.

Свойства

  • 12.1 Используйте точечную нотацию для доступа к свойствам.

    const luke = {
      jedi: true,
      age: 28,
    };
    
    // плохо
    const isJedi = luke['jedi'];
    
    // хорошо
    const isJedi = luke.jedi;
    
  • 12.2 Используйте квадратные скобки для доступа к свойству, имя которого хранится в переменной.

    const luke = {
      jedi: true,
      age: 28,
    };
    
    function getProp(prop) {
      return luke[prop];
    }
    
    const isJedi = getProp('jedi');
    

Переменные

  • 13.1 Всегда используйте const для объявления переменных. В противном случае переменная будет объявлена глобальной. Необходимо избегать загрязнения глобального пространства имен.

    // плохо
    superPower = new SuperPower();
    
    // хорошо
    const superPower = new SuperPower();
    
  • 13.2 Используйте const для объявления каждой переменной.

    Почему? Так проще добавлять новое объявление переменной, не заботясь о замене ; на ,

    // плохо
    const items = getItems(),
        goSportsTeam = true,
        dragonball = 'z';
    
    // плохо
    // (сравните с предыдущим примером и найдите ошибку)
    const items = getItems(),
        goSportsTeam = true;
        dragonball = 'z';
    
    // хорошо
    const items = getItems();
    const goSportsTeam = true;
    const dragonball = 'z';
    
  • 13.3 Объявите сначала все const, а затем все let.

Почему? Это удобно, когда позднее нужно будет присвоить значение одной из переменных в зависимости от уже присвоенных значений предыдущих переменных.

```javascript
// плохо
let i, len, dragonball,
    items = getItems(),
    goSportsTeam = true;

// плохо
let i;
const items = getItems();
let dragonball;
const goSportsTeam = true;
let len;

// хорошо
const goSportsTeam = true;
const items = getItems();
let dragonball;
let i;
let length;
```
  • 13.4 Объявляйте переменные там, где они вам необходимы, но делайте это оправданно

Почему? Область видимости для let и const переменных - блок, а не функция

```javascript
// хорошо
function() {
  test();
  console.log('делаю что-то..');

  //..делаю что-то еще..

  const name = getName();

  if (name === 'test') {
    return false;
  }

  return name;
}

// плохо - unnecessary function call
function(hasName) {
  const name = getName();

  if (!hasName) {
    return false;
  }

  this.setFirstName(name);

  return true;
}

// хорошо
function(hasName) {
  if (!hasName) {
    return false;
  }

  const name = getName();
  this.setFirstName(name);

  return true;
}
```

Область видимости и "поднятие"

  • 14.1 Объявление переменных var "поднимается" в начало области видимости, а присвоение — нет. Объявление const и let работает по новой концепции Temporal Dead Zones (TDZ). Важно знать, почему использование typeof больше небезопасно.

    // Мы знаем, что это не будет работать
    // если нет глобальной переменной notDefined
    function example() {
      console.log(notDefined); // => throws a ReferenceError
    }
    
    // Объявление переменной после попытки ее использования
    // будет работать по правилу "поднятия"
    // Заметьте, что присвоение значения `true` не поднимается
    function example() {
      console.log(declaredButNotAssigned); // => undefined
      var declaredButNotAssigned = true;
    }
    
    // Интерпретатор переносит объявление переменной
    // к началу области видимости.
    // Что значит, что предыдущий пример можно переписать так:
    function example() {
      let declaredButNotAssigned;
      console.log(declaredButNotAssigned); // => undefined
      declaredButNotAssigned = true;
    }
    
    // Использование const и let
    function example() {
      console.log(declaredButNotAssigned); // => throws a ReferenceError
      console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
      const declaredButNotAssigned = true;
    }
    
  • 14.2 Присвоение анонимной функции поднимает наверх области видимости переменную, но не функцию.

    function example() {
      console.log(anonymous); // => undefined
    
      anonymous(); // => TypeError anonymous is not a function
    
      var anonymous = function() {
        console.log('anonymous function expression');
      };
    }
    
  • 14.3 Присвоение именованной функции поднимает переменную, не ее имя функции или ее тело.

    function example() {
      console.log(named); // => undefined
    
      named(); // => TypeError named is not a function
    
      superPower(); // => ReferenceError superPower is not defined
    
      var named = function superPower() {
        console.log('Flying');
      };
    }
    
    // То же самое происходит, когда имя функции и имя переменной совпадают.
    function example() {
      console.log(named); // => undefined
    
      named(); // => TypeError named is not a function
    
      var named = function named() {
        console.log('named');
      }
    }
    
  • 14.4 Function declarations поднимают и имя, и тело функции.

    function example() {
      superPower(); // => Flying
    
      function superPower() {
        console.log('Flying');
      }
    }
    
  • Подробнее можно прочитать в статье JavaScript Scoping & Hoisting by Ben Cherry.

Операторы сравнения и равенство

  • 15.1 Используйте === и!== вместо == и !=.

  • 15.2 Условные выражения вычисляются посредством приведения методом ToBoolean и всегда следуют следующим правилам:

    • Objects соответствует true
    • Undefined соответствует false
    • Null соответствует false
    • Booleans остаются неизменными
    • Numbers соответствует false если имеют значения +0, -0, или NaN, иначе true
    • Strings соответствует false если является пустой строкой '', иначе true
    if ([0]) {
      // true
      // Массив(Array) является объектом, объекты преобразуются в true
    }
    
  • 15.3 Используйте короткий синтаксис.

    // плохо
    if (name !== '') {
      // ...код...
    }
    
    // хорошо
    if (name) {
      // ...код...
    }
    
    // плохо
    if (collection.length > 0) {
      // ...код...
    }
    
    // хорошо
    if (collection.length) {
      // ...код...
    }
    
  • 15.4 Подробнее можно прочитать в статье Truth Equality and JavaScript by Angus Croll.

Блоки кода

  • 16.1 Используйте фигурные скобки для всех многострочных блоков.

    // плохо
    if (test)
      return false;
    
    // хорошо
    if (test) return false;
    
    // хорошо
    if (test) {
      return false;
    }
    
    // плохо
    function() { return false; }
    
    // хорошо
    function() {
      return false;
    }
    
  • 16.2 Если вы используете многострочные блоки с if и else, размещайте else на одной строке с закрывающей скобкой блока if

    // плохо
    if (test) {
      thing1();
      thing2();
    }
    else {
      thing3();
    }
    
    // хорошо
    if (test) {
      thing1();
      thing2();
    } else {
      thing3();
    }
    

Комментарии

  • 17.1 Use /** ... */ для многострочных комментариев. Включите описание, опишите типы и значения для всех параметров и возвращаемых значений.

    // плохо
    // make() возвращает новый элемент
    // основываясь на получаемом имени тэга
    //
    // @param {String} tag
    // @return {Element} element
    function make(tag) {
    
      // ...код...
    
      return element;
    }
    
    // хорошо
    /**
     * make() возвращает новый элемент
     * основываясь на получаемом имени тэга
     *
     * @param {String} tag
     * @return {Element} element
     */
    function make(tag) {
    
      // ...код...
    
      return element;
    }
    
  • 17.2 Используйте // для однострочных комментариев. Размещайте однострочные комментарии на новой строке над темой комментария. Добавляйте пустую строку перед комментарием.

    // плохо
    const active = true;  // is current tab
    
    // хорошо
    // is current tab
    const active = true;
    
    // плохо
    function getType() {
      console.log('fetching type...');
      // set the default type to 'no type'
      const type = this._type || 'no type';
    
      return type;
    }
    
    // хорошо
    function getType() {
      console.log('fetching type...');
    
      // set the default type to 'no type'
      const type = this._type || 'no type';
    
      return type;
    }
    
  • 17.3 Префикс FIXME или TODO помогает другим разработчикам быстро понять, что вы указываете на проблему, к которой нужно вернуться в дальнейшем, или если вы предлагаете решение проблемы, которое должно быть реализовано. Эти комментарии отличаются от обычных, так как они призывают к действию: FIXME -- нужно разобраться, TODO -- нужно реализовать.

  • 17.4 Используйте // FIXME: чтобы указать на проблему

    class Calculator extends Abacus {
      constructor() {
        super();
    
        // FIXME: не нужно использовать глобальную переменную
        total = 0;
      }
    }
    
  • 17.5 Use // TODO: для указания решения проблемы

    class Calculator extends Abacus {
      constructor() {
        super();
    
        // TODO: должна быть возможность изменять значение через параметр функции
        this.total = 0;
      }
    }
    

Пробелы

  • 18.1 Используйте табуляцию из 4 пробелов

    // плохо
    function() {
    ∙∙const name;
    }
    
    // плохо
    function() {
    ∙const name;
    }
    
    // хорошо
    function() {
    ∙∙∙∙const name;
    }
    
  • 18.2 Устанавливайте один пробел перед открывающей скобкой.

    // плохо
    function test(){
      console.log('test');
    }
    
    // хорошо
    function test() {
      console.log('test');
    }
    
    // плохо
    dog.set('attr',{
      age: '1 year',
      breed: 'Bernese Mountain Dog',
    });
    
    // хорошо
    dog.set('attr', {
      age: '1 year',
      breed: 'Bernese Mountain Dog',
    });
    
  • 18.3 Устанавливайте один пробел перед открывающей скобкой операторов управления (if, while etc.). Не ставьте пробелы перед аргументами при вызове и объявлении функции.

    // плохо
    if(isJedi) {
      fight ();
    }
    
    // хорошо
    if (isJedi) {
      fight();
    }
    
    // плохо
    function fight () {
      console.log ('Swooosh!');
    }
    
    // хорошо
    function fight() {
      console.log('Swooosh!');
    }
    
  • 18.4 Выделяйте операторы пробелами.

    // плохо
    const x=y+5;
    
    // хорошо
    const x = y + 5;
    
  • 18.5 Оставляйте одну новую строку в конце файла.

    // плохо
    (function(global) {
      // ...stuff...
    })(this);
    
    // плохо
    (function(global) {
      // ...stuff...
    })(this);↵
    ↵
    
    // хорошо
    (function(global) {
      // ...stuff...
    })(this);↵
    
  • 18.6 Используйте отступы, когда делаете цепочки вызовов. Ставьте в начале строки точку, которая будет указывать на то, что в этой строке вызов метода, а не новое выражение.

    // плохо
    $('#items').find('.selected').highlight().end().find('.open').updateCount();
    
    // плохо
    $('#items').
      find('.selected').
        highlight().
        end().
      find('.open').
        updateCount();
    
    // хорошо
    $('#items')
      .find('.selected')
        .highlight()
        .end()
      .find('.open')
        .updateCount();
    
    // плохо
    const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
        .attr('width', (radius + margin) * 2).append('svg:g')
        .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
        .call(tron.led);
    
    // хорошо
    const leds = stage.selectAll('.led')
        .data(data)
      .enter().append('svg:svg')
        .classed('led', true)
        .attr('width', (radius + margin) * 2)
      .append('svg:g')
        .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
        .call(tron.led);
    
  • 18.7 Оставляйте пустую строку после блоков кода перед следующим выражением.

    // плохо
    if (foo) {
      return bar;
    }
    return baz;
    
    // хорошо
    if (foo) {
      return bar;
    }
    
    return baz;
    
    // плохо
    const obj = {
      foo() {
      },
      bar() {
      },
    };
    return obj;
    
    // хорошо
    const obj = {
      foo() {
      },
    
      bar() {
      },
    };
    
    return obj;
    
    // плохо
    const arr = [
      function foo() {
      },
      function bar() {
      },
    ];
    return arr;
    
    // хорошо
    const arr = [
      function foo() {
      },
    
      function bar() {
      },
    ];
    
    return arr;
    

Запятые

  • 19.1 Запятые в начале строки: Нет.

    // плохо
    const story = [
        once
      , upon
      , aTime
    ];
    
    // хорошо
    const story = [
      once,
      upon,
      aTime,
    ];
    
    // плохо
    const hero = {
        firstName: 'Ada'
      , lastName: 'Lovelace'
      , birthYear: 1815
      , superPower: 'computers'
    };
    
    // хорошо
    const hero = {
      firstName: 'Ada',
      lastName: 'Lovelace',
      birthYear: 1815,
      superPower: 'computers',
    };
    
  • 19.2 Дополнительная запятая в конце объектов: Нет.

    // Плохо
    const hero = {
      firstName: 'Dana',
      lastName: 'Scully',
    };
    
    const heroes = [
      'Batman',
      'Superman',
    ];
    
    // Хорошо
    const hero = {
      firstName: 'Dana',
      lastName: 'Scully'
    };
    
    const heroes = [
      'Batman',
      'Superman'
    ];  
    

Точки с запятой

  • 20.1 Да.

    // плохо
    (function() {
      const name = 'Skywalker'
      return name
    })()
    
    // хорошо
    (() => {
      const name = 'Skywalker';
      return name;
    })();
    
    // хорошо (защита от ситуации, когда функция становится аргументом при объединении файлов с IIFE)
    ;(() => {
      const name = 'Skywalker';
      return name;
    })();
    

    Подробнее.

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

  • 21.1 Выполняйте приведение типов в начале операции.

  • 21.2 Строки:

    //  => this.reviewScore = 9;
    
    // плохо
    const totalScore = this.reviewScore + '';
    
    // хорошо
    const totalScore = String(this.reviewScore);
    
  • 21.3 Числа: Используйте Number для приведения типа and parseInt всегда с указанием основания для преобразования строки

    const inputValue = '4';
    
    // плохо
    const val = new Number(inputValue);
    
    // плохо
    const val = +inputValue;
    
    // плохо
    const val = inputValue >> 0;
    
    // плохо
    const val = parseInt(inputValue);
    
    // хорошо
    const val = Number(inputValue);
    
    // хорошо
    const val = parseInt(inputValue, 10);
    
  • 21.4 Если по какой-либо причине на parseInt тратится больше всего ресурсов и необходимо использовать побитовый сдвиг из соображений быстродействия, оставьте комментарий с объяснением причин.

    // хорошо
    /**
     * этот код медленно работал из-за parseInt
     * побитовый сдвиг строки для приведения ее к числу
     * работает значительно быстрее.
     */
    const val = inputValue >> 0;
    
  • 21.5 Примечание: Будьте осторожны с побитовыми операциями. Числа в JavaScript являются 64-битными значениями, но побитовые операции всегда возвращают 32-битные значения. (Источник). Побитовые операции над числами, значение которых выходит за 32 бита, могут привести к неожиданному поведению. Обсуждение Максимальное 32-битное целое - 2 147 483 647:

    2147483647 >> 0 //=> 2147483647
    2147483648 >> 0 //=> -2147483648
    2147483649 >> 0 //=> -2147483647
    
  • 21.6 Логические типы:

    const age = 0;
    
    // плохо
    const hasAge = new Boolean(age);
    
    // хорошо
    const hasAge = Boolean(age);
    
    // хорошо
    const hasAge = !!age;
    

Соглашение об именовании

  • 22.1 Избегайте однобуквенных имен. Имена должны давать представление о том, для чего используется переменная/функция.

    // плохо
    function q() {
      // ...код...
    }
    
    // хорошо
    function query() {
      // ..код..
    }
    
  • 22.2 Используйте camelCase для именования объектов, функций и переменных.

    // плохо
    const OBJEcttsssss = {};
    const this_is_my_object = {};
    function c() {}
    
    // хорошо
    const thisIsMyObject = {};
    function thisIsMyFunction() {}
    
  • 22.3 Используйте PascalCase для именования конструкторов или классов

    // плохо
    function user(options) {
      this.name = options.name;
    }
    
    const bad = new user({
      name: 'nope',
    });
    
    // хорошо
    class User {
      constructor(options) {
        this.name = options.name;
      }
    }
    
    const good = new User({
      name: 'yup',
    });
    
  • 22.4 Используйте _ в начале имени приватных свойств.

    // плохо
    this.__firstName__ = 'Panda';
    this.firstName_ = 'Panda';
    
    // хорошо
    this._firstName = 'Panda';
    
  • 22.5 Не сохраняйте ссылку на this. Используйте arrow functions или Function#bind.

    // плохо
    function foo() {
      const self = this;
      return function() {
        console.log(self);
      };
    }
    
    // плохо
    function foo() {
      const that = this;
      return function() {
        console.log(that);
      };
    }
    
    // хорошо
    function foo() {
      return () => {
        console.log(this);
      };
    }
    
  • 22.6 Если в вашем файле экспортируется один класс, имя файла должно совпадать с именем класса.

    // file contents
    class CheckBox {
      // ...
    }
    export default CheckBox;
    
    // in some other file
    // плохо
    import CheckBox from './checkBox';
    
    // плохо
    import CheckBox from './check_box';
    
    // хорошо
    import CheckBox from './CheckBox';
    
  • 22.7 Используйте camelCase, если экспортируется функция. Имя файла должно совпадать с именем функции.

    function makeStyleGuide() {
    }
    
    export default makeStyleGuide;
    
  • 22.8 Используйте PascalCase, если экспортируется singleton / библиотека функций / объект.

    const AirbnbStyleGuide = {
      es6: {
      }
    };
    
    export default AirbnbStyleGuide;
    

Функции доступа get и set

  • 23.1 Функции доступа к свойствам не обязательны.

  • 23.2 Если вы создаете функцию доступа, используйте getVal() и setVal('hello').

    // плохо
    dragon.age();
    
    // хорошо
    dragon.getAge();
    
    // плохо
    dragon.age(25);
    
    // хорошо
    dragon.setAge(25);
    
  • 23.3 Если свойство является логическим(boolean), используйте isVal() или hasVal().

    // плохо
    if (!dragon.age()) {
      return false;
    }
    
    // хорошо
    if (!dragon.hasAge()) {
      return false;
    }
    
  • 23.4 Вы можете создавать функции get() и set(), но не добавляйте свойства, которые не могут быть изменены через эти функции.

    class Jedi {
      constructor(options = {}) {
        const lightsaber = options.lightsaber || 'blue';
        this.set('lightsaber', lightsaber);
      }
    
      set(key, val) {
        this[key] = val;
      }
    
      get(key) {
        return this[key];
      }
    }
    

События

  • 24.1 Подключая набор данных к событиям (как DOM-событиям, так и более частным, например, в Backbone), передавайте объект вместо просто значения. Это позволяет впоследствии добавлять больше данных в объект события без переписывания хэндлеров.

    // плохо
    $(this).trigger('listingUpdated', listing.id);
    
    ...
    
    $(this).on('listingUpdated', function(e, listingId) {
      // do something with listingId
    });
    
    // хорошо
    $(this).trigger('listingUpdated', { listingId: listing.id });
    
    ...
    
    $(this).on('listingUpdated', function(e, data) {
      // do something with data.listingId
    });
    

jQuery

  • 25.1 Для jQuery объектов используйте префикс $.

    // плохо
    const sidebar = $('.sidebar');
    
    // хорошо
    const $sidebar = $('.sidebar');
    
    // хорошо
    const $sidebarBtn = $('.sidebar-btn');
    
  • 25.2 Кэшируйте jQuery-запросы.

    // плохо
    function setSidebar() {
      $('.sidebar').hide();
    
      // ...код...
    
      $('.sidebar').css({
        'background-color': 'pink'
      });
    }
    
    // хорошо
    function setSidebar() {
      const $sidebar = $('.sidebar');
      $sidebar.hide();
    
      // ...код...
    
      $sidebar.css({
        'background-color': 'pink'
      });
    }
    
  • 25.3 Для DOM-запросов используйте каскадный синтаксис $('.sidebar ul') или родитель > потомок $('.sidebar > ul'). jsPerf

  • 25.4 Use find с уже найденными объектами.

    // плохо
    $('ul', '.sidebar').hide();
    
    // плохо
    $('.sidebar').find('ul').hide();
    
    // хорошо
    $('.sidebar ul').hide();
    
    // хорошо
    $('.sidebar > ul').hide();
    
    // хорошо
    $sidebar.find('ul').hide();
    

Совместимость ECMAScript 5

Стили ECMAScript 6

  • 27.1 Это ссылки на особенности es6.
  1. Arrow Functions
  2. Классы
  3. Короткая запись объектов
  4. Лаконичность объектов
  5. Программно-созданные свойства объектов
  6. Шаблоны строк
  7. Destructuring
  8. Параметры по умолчанию
  9. Остаточные параметры
  10. Array Spreads
  11. Let и Const
  12. Итераторы и генераторы
  13. Модули

Тестирование

  • 28.1 Да.

    function() {
      return true;
    }
    

Быстродействие

⬆ back to top

Ресурсы

Изучение ES6

Прочитайте это

Инструменты

Другие руководства по стилю

Другие стили

Дальнейшее прочтение

Книги

Блоги

Подкасты

Лицензия

(The MIT License)

Copyright (c) 2014 Airbnb

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.