Photo by Pankaj Patel on Unsplash
Руководство по стилю JavaScript от Airbnb()
Разумный подход к JavaScript.
Другие руководства по стилю
Переведено из Airbnb JavaScript Style Guide.
Типы (Types)
- 1.1 Примитивы (Primitives): Вы обращаетесь к примитивным типам напрямую.
stringnumberbooleannullundefined
const foo = 1;
let bar = foo;
bar = 9;
console.log(foo, bar); // => 1, 9
- 1.2 Сложные (Complex): Вы обращаетесь к сложным типам по ссылке (by reference).
objectarrayfunction
const foo = [1, 2];
const bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9
Ссылки (References)
- 2.1 Используйте
constдля всех ваших ссылок; избегайте использованияvar. eslint:prefer-const,no-const-assign
Почему? Это гарантирует, что вы не сможете переназначить свои ссылки, что может привести к ошибкам и трудночитаемому коду.
// bad
var a = 1;
var b = 2;
// good
const a = 1;
const b = 2;
- 2.2 Если вам нужно переназначить ссылки, используйте
letвместоvar. eslint:no-varjscs:disallowVar
Почему?
letимеет блочную область видимости (block-scoped), в то время какvarимеет функциональную область видимости (function-scoped).
// bad
var count = 1;
if (true) {
count += 1;
}
// good, 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
Объекты (Objects)
- 3.1 Используйте литеральный синтаксис для создания объектов. eslint rules:
no-new-object.
// bad
const item = new Object();
// good
const item = {};
- 3.2 Не используйте зарезервированные слова в качестве ключей. Это не будет работать в IE8. Подробнее. Однако их можно использовать в модулях ES6 и серверном коде. jscs:
disallowIdentifierNames
// bad
const superman = {
default: { clark: 'kent' },
private: true,
};
// good
const superman = {
defaults: { clark: 'kent' },
hidden: true,
};
- 3.3 Используйте читаемые синонимы вместо зарезервированных слов. jscs:
disallowIdentifierNames
// bad
const superman = {
class: 'alien',
};
// bad
const superman = {
klass: 'alien',
};
// good
const superman = {
type: 'alien',
};
- 3.4 Используйте вычисляемые имена свойств (computed property names) при создании объектов с динамическими именами свойств.
Почему? Они позволяют определить все свойства объекта в одном месте.
function getKey(k) {
return `a key named ${k}`;
}
// bad
const obj = {
id: 5,
name: 'San Francisco',
};
obj[getKey('enabled')] = true;
// good
const obj = {
id: 5,
name: 'San Francisco',
[getKey('enabled')]: true,
};
- 3.5 Используйте сокращенную запись методов объекта (object method shorthand). eslint:
object-shorthandjscs:requireEnhancedObjectLiterals
// bad
const atom = {
value: 1,
addValue: function (value) {
return atom.value + value;
},
};
// good
const atom = {
value: 1,
addValue(value) {
return atom.value + value;
},
};
- 3.6 Используйте сокращенную запись значений свойств (property value shorthand). eslint:
object-shorthandjscs:requireEnhancedObjectLiterals
Почему? Это короче и более описательно.
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
lukeSkywalker: lukeSkywalker,
};
// good
const obj = {
lukeSkywalker,
};
- 3.7 Группируйте ваши сокращения в начале объявления объекта.
Почему? Легче увидеть, какие свойства используют сокращение.
const anakinSkywalker = 'Anakin Skywalker';
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
episodeOne: 1,
twoJediWalkIntoACantina: 2,
lukeSkywalker,
episodeThree: 3,
mayTheFourth: 4,
anakinSkywalker,
};
// good
const obj = {
lukeSkywalker,
anakinSkywalker,
episodeOne: 1,
twoJediWalkIntoACantina: 2,
episodeThree: 3,
mayTheFourth: 4,
};
- 3.8 Ставьте кавычки только вокруг свойств, которые являются недопустимыми идентификаторами. eslint:
quote-propsjscs:disallowQuotedKeysInObjects
Почему? В целом мы считаем это субъективно более легким для чтения. Это улучшает подсветку синтаксиса, а также легче оптимизируется многими движками JS.
// bad
const bad = {
'foo': 3,
'bar': 4,
'data-blah': 5,
};
// good
const good = {
foo: 3,
bar: 4,
'data-blah': 5,
};
Массивы (Arrays)
- 4.1 Используйте литеральный синтаксис для создания массивов. eslint:
no-array-constructor
// bad
const items = new Array();
// good
const items = [];
- 4.2 Используйте Array#push вместо прямого присваивания для добавления элементов в массив.
const someStack = [];
// bad
someStack[someStack.length] = 'abracadabra';
// good
someStack.push('abracadabra');
- 4.3 Используйте спреды массивов
...для копирования массивов.
// bad
const len = items.length;
const itemsCopy = [];
let i;
for (i = 0; i < len; i++) {
itemsCopy[i] = items[i];
}
// good
const itemsCopy = [...items];
- 4.4 Чтобы преобразовать массивоподобный объект (array-like object) в массив, используйте Array#from.
const foo = document.querySelectorAll('.foo');
const nodes = Array.from(foo);
- 4.5 Используйте инструкции возврата в колбэках методов массива. Допустимо опустить return, если тело функции состоит из одной инструкции, следующей за 8.2. eslint:
array-callback-return
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map(x => x + 1);
// bad
const flat = {};
[[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
const flatten = memo.concat(item);
flat[index] = memo.concat(item);
});
// good
const flat = {};
[[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
const flatten = memo.concat(item);
flat[index] = flatten;
return flatten;
});
// bad
inbox.filter((msg) => {
const { subject, author } = msg;
if (subject === 'Mockingbird') {
return author === 'Harper Lee';
} else {
return false;
}
});
// good
inbox.filter((msg) => {
const { subject, author } = msg;
if (subject === 'Mockingbird') {
return author === 'Harper Lee';
}
return false;
});
Деструктуризация (Destructuring)
- 5.1 Используйте деструктуризацию объекта при доступе и использовании нескольких свойств объекта. jscs:
requireObjectDestructuring
Почему? Деструктуризация избавляет вас от создания временных ссылок для этих свойств.
// bad
function getFullName(user) {
const firstName = user.firstName;
const lastName = user.lastName;
return `${firstName} ${lastName}`;
}
// good
function getFullName(user) {
const { firstName, lastName } = user;
return `${firstName} ${lastName}`;
}
// best
function getFullName({ firstName, lastName }) {
return `${firstName} ${lastName}`;
}
- 5.2 Используйте деструктуризацию массива. jscs:
requireArrayDestructuring
const arr = [1, 2, 3, 4];
// bad
const first = arr[0];
const second = arr[1];
// good
const [first, second] = arr;
- 5.3 Используйте деструктуризацию объекта для нескольких возвращаемых значений, а не деструктуризацию массива.
Почему? Вы можете добавлять новые свойства или изменять порядок вещей, не нарушая места вызова (call sites).
// bad
function processInput(input) {
// then a miracle occurs
return [left, right, top, bottom];
}
// the caller needs to think about the order of return data
const [left, __, top] = processInput(input);
// good
function processInput(input) {
// then a miracle occurs
return { left, right, top, bottom };
}
// the caller selects only the data they need
const { left, right } = processInput(input);
Строки (Strings)
- 6.1 Используйте одинарные кавычки
''для строк. eslint:quotesjscs:validateQuoteMarks
// bad
const name = "Capt. Janeway";
// good
const name = 'Capt. Janeway';
- 6.2 Строки длиной более 100 символов не должны записываться в несколько строк с использованием конкатенации строк.
- 6.3 Примечание: При чрезмерном использовании длинные строки с конкатенацией могут повлиять на производительность. jsPerf & Discussion.
// bad
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.';
// bad
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.';
// good
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 При программном построении строк используйте шаблонные строки (template strings) вместо конкатенации. eslint:
prefer-templatetemplate-curly-spacingjscs:requireTemplateStrings
Почему? Шаблонные строки дают вам читаемый, лаконичный синтаксис с новыми строками и функциями интерполяции строк.
// bad
function sayHi(name) {
return 'How are you, ' + name + '?';
}
// bad
function sayHi(name) {
return ['How are you, ', name, '?'].join();
}
// bad
function sayHi(name) {
return `How are you, ${ name }?`;
}
// good
function sayHi(name) {
return `How are you, ${name}?`;
}
- 6.5 Никогда не используйте
eval()для строки, это открывает слишком много уязвимостей.
Функции (Functions)
- 7.1 Используйте объявления функций (function declarations) вместо функциональных выражений (function expressions). jscs:
requireFunctionDeclarations
Почему? Объявления функций именуются, поэтому их легче идентифицировать в стеке вызовов. Кроме того, объявления функций поднимаются (hoisted), тогда как функциональные выражения - нет. Это правило позволяет Стрелочным функциям полностью заменить функциональные выражения.
// bad
const foo = function () {
};
// good
function foo() {
}
- 7.2 Обертывание немедленно вызываемых функциональных выражений (IIFE): eslint:
wrap-iifejscs:requireParenthesesAroundIIFE
Почему? IIFE - это единая единица; обертывание как функции, так и ее вызова в скобки делает это очевидным. Обратите внимание, что в мире с модулями вам почти не нужны IIFE.
// immediately-invoked function expression (IIFE)
(function () {
console.log('Welcome to the Internet. Please follow me.');
}());
-
7.3 Никогда не объявляйте функцию в нефункциональном блоке (if, while и т. д.). Вместо этого присвойте функцию переменной. Браузеры позволят вам это сделать, но все они интерпретируют это по-разному. eslint:
no-loop-func -
7.4 Примечание: ECMA-262 определяет
blockкак список инструкций. Объявление функции не является инструкцией. Прочитайте примечание ECMA-262 по этому вопросу.
// bad
if (currentUser) {
function test() {
console.log('Nope.');
}
}
// good
let test;
if (currentUser) {
test = () => {
console.log('Yup.');
};
}
- 7.5 Никогда не называйте параметр
arguments. Это будет иметь приоритет над объектомarguments, который дается каждой области видимости функции.
// bad
function nope(name, options, arguments) {
// ...stuff...
}
// good
function yup(name, options, args) {
// ...stuff...
}
- 7.6 Никогда не используйте
arguments, выбирайте rest-синтаксис...вместо этого.prefer-rest-params
Почему?
...делает явным, какие аргументы вы хотите вытащить. Кроме того, rest-аргументы - это настоящий массив, а не просто массивоподобный объект, какarguments.
// bad
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join('');
}
// good
function concatenateAll(...args) {
return args.join('');
}
- 7.7 Используйте синтаксис параметров по умолчанию вместо изменения аргументов функции.
// really bad
function handleThings(opts) {
// No! We shouldn't mutate function arguments.
// Double bad: if opts is false it will be set to an object which may
// be what you want but it can cause subtle bugs.
opts = opts || {};
// ...
}
// still bad
function handleThings(opts) {
if (opts === void 0) {
opts = {};
}
// ...
}
// good
function handleThings(opts = {}) {
// ...
}
- 7.8 Избегайте побочных эффектов с параметрами по умолчанию.
Почему? Их сложно понять.
var b = 1;
// bad
function count(a = b++) {
console.log(a);
}
count(); // 1
count(); // 2
count(3); // 3
count(); // 3
- 7.9 Всегда ставьте параметры по умолчанию последними.
// bad
function handleThings(opts = {}, name) {
// ...
}
// good
function handleThings(name, opts = {}) {
// ...
}
- 7.10 Никогда не используйте конструктор Function для создания новой функции.
Почему? Создание функции таким образом оценивает строку аналогично eval(), что открывает уязвимости.
// bad
var add = new Function('a', 'b', 'return a + b');
// still bad
var subtract = Function('a', 'b', 'return a - b');
- 7.11 Пробелы в сигнатуре функции.
Почему? Последовательность - это хорошо, и вам не нужно добавлять или удалять пробел при добавлении или удалении имени.
// bad
const f = function(){};
const g = function (){};
const h = function() {};
// good
const x = function () {};
const y = function a() {};
- 7.12 Никогда не изменяйте параметры. eslint:
no-param-reassign
Почему? Манипулирование объектами, переданными в качестве параметров, может вызвать нежелательные побочные эффекты у исходного вызывающего.
// bad
function f1(obj) {
obj.key = 1;
};
// good
function f2(obj) {
const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
};
- 7.13 Никогда не переназначайте параметры. eslint:
no-param-reassign
Почему? Переназначение параметров может привести к неожиданному поведению, особенно при доступе к объекту
arguments. Это также может вызвать проблемы с оптимизацией, особенно в V8.
```javascript
// bad
function f1(a) {
a = 1;
}
function f2(a) {
if (!a) { a = 1; }
}
// good
function f3(a) {
const b = a || 1;
}
function f4(a = 1) {
}
```
Стрелочные функции (Arrow Functions)
- 8.1 Когда вам нужно использовать функциональное выражение (например, при передаче анонимной функции), используйте запись стрелочной функции. eslint:
prefer-arrow-callback,arrow-spacingjscs:requireArrowFunctions
Почему? Она создает версию функции, которая выполняется в контексте
this, что вам обычно и нужно, и это более лаконичный синтаксис.
Почему нет? Если у вас есть довольно сложная функция, вы можете переместить эту логику в собственное именованное объявление функции.
// bad
[1, 2, 3].map(function (x) {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
- 8.2 Если тело функции состоит из одного выражения, возвращающего выражение без побочных эффектов, опустите фигурные скобки и используйте неявный возврат. В противном случае сохраните фигурные скобки и используйте оператор
return. eslint:arrow-parens,arrow-body-stylejscs:disallowParenthesesAroundArrowParam,requireShorthandArrowFunctions
Почему? Синтаксический сахар. Это читается лучше, когда несколько функций соединены в цепочку.
Почему нет? Если вы планируете вернуть объект.
// bad
[1, 2, 3].map(number => {
const nextNumber = number + 1;
`A string containing the ${nextNumber}.`;
});
// good
[1, 2, 3].map(number => `A string containing the ${number}.`);
// good
[1, 2, 3].map((number) => {
const nextNumber = number + 1;
return `A string containing the ${nextNumber}.`;
});
- 8.3 Если выражение занимает несколько строк, оберните его в круглые скобки для лучшей читаемости.
Почему? Это ясно показывает, где начинается и где заканчивается функция.
// bad
[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.'
);
// good
[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 Если ваша функция принимает один аргумент и не использует фигурные скобки, опустите круглые скобки. В противном случае всегда включайте круглые скобки вокруг аргументов. eslint:
arrow-parensjscs:disallowParenthesesAroundArrowParam
Почему? Меньше визуального шума.
// bad
[1, 2, 3].map((x) => x * x);
// good
[1, 2, 3].map(x => x * x);
// good
[1, 2, 3].map(number => (
`A long string with the ${number}. It’s so long that we’ve broken it ` +
'over multiple lines!'
));
// bad
[1, 2, 3].map(x => {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
- 8.5 Избегайте путаницы между синтаксисом стрелочной функции (
=>) и операторами сравнения (<=,>=). eslint:no-confusing-arrow
// bad
const itemHeight = item => item.height > 256 ? item.largeSize : item.smallSize;
// bad
const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize;
// good
const itemHeight = item => { return item.height > 256 ? item.largeSize : item.smallSize; }
Конструкторы (Constructors)
- 9.1 Всегда используйте
class. Избегайте манипулированияprototypeнапрямую.
Почему? Синтаксис
classболее лаконичный и понятный.
// bad
function Queue(contents = []) {
this._queue = [...contents];
}
Queue.prototype.pop = function () {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
}
// good
class Queue {
constructor(contents = []) {
this._queue = [...contents];
}
pop() {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
}
}
- 9.2 Используйте
extendsдля наследования.
Почему? Это встроенный способ наследования функциональности прототипа без нарушения
instanceof.
// bad
const inherits = require('inherits');
function PeekableQueue(contents) {
Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function () {
return this._queue[0];
}
// good
class PeekableQueue extends Queue {
peek() {
return this._queue[0];
}
}
- 9.3 Методы могут возвращать
this, чтобы помочь с цепочкой методов (method chaining).
// bad
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
// good
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()}`;
}
}
- 9.5 У классов есть конструктор по умолчанию, если он не указан. Пустой конструктор или тот, который просто делегирует родительскому классу, не нужен.
no-useless-constructor
// bad
class Jedi {
constructor() {}
getName() {
return this.name;
}
}
// bad
class Rey extends Jedi {
constructor(...args) {
super(...args);
}
}
// good
class Rey extends Jedi {
constructor(...args) {
super(...args);
this.name = 'Rey';
}
}
Модули (Modules)
- 10.1 Всегда используйте модули (
import/export) вместо нестандартной модульной системы. Вы всегда можете транспилировать в предпочитаемую вами модульную систему.
Почему? Модули - это будущее, давайте начнем использовать будущее сейчас.
// bad
const AirbnbStyleGuide = require('./AirbnbStyleGuide');
module.exports = AirbnbStyleGuide.es6;
// ok
import AirbnbStyleGuide from './AirbnbStyleGuide';
export default AirbnbStyleGuide.es6;
// best
import { es6 } from './AirbnbStyleGuide';
export default es6;
- 10.2 Не используйте импорт с подстановочными знаками (wildcard imports).
Почему? Это гарантирует, что у вас есть один экспорт по умолчанию.
// bad
import * as AirbnbStyleGuide from './AirbnbStyleGuide';
// good
import AirbnbStyleGuide from './AirbnbStyleGuide';
- 10.3 И не экспортируйте напрямую из импорта.
Почему? Хотя однострочная запись лаконична, наличие одного четкого способа импорта и одного четкого способа экспорта делает вещи последовательными.
// bad
// filename es6.js
export { es6 as default } from './airbnbStyleGuide';
// good
// filename es6.js
import { es6 } from './AirbnbStyleGuide';
export default es6;
Итераторы и генераторы (Iterators and Generators)
- 11.1 Не используйте итераторы. Отдавайте предпочтение функциям высшего порядка JavaScript, таким как
map()иreduce(), вместо циклов, таких какfor-of. eslint:no-iterator
Почему? Это обеспечивает соблюдение нашего правила неизменяемости. Работа с чистыми функциями, которые возвращают значения, проще для понимания, чем побочные эффекты.
eslint rules: no-iterator.
const numbers = [1, 2, 3, 4, 5];
// bad
let sum = 0;
for (let num of numbers) {
sum += num;
}
sum === 15;
// good
let sum = 0;
numbers.forEach(num => sum += num);
sum === 15;
// best (use the functional force)
const sum = numbers.reduce((total, num) => total + num, 0);
sum === 15;
- 11.2 Не используйте генераторы пока.
Почему? Они пока плохо транспилируются в ES5.
Свойства (Properties)
- 12.1 Используйте точечную нотацию (dot notation) при доступе к свойствам. eslint:
dot-notationjscs:requireDotNotation
const luke = {
jedi: true,
age: 28,
};
// bad
const isJedi = luke['jedi'];
// good
const isJedi = luke.jedi;
- 12.2 Используйте скобочную нотацию
[]при доступе к свойствам с помощью переменной.
const luke = {
jedi: true,
age: 28,
};
function getProp(prop) {
return luke[prop];
}
const isJedi = getProp('jedi');
Переменные (Variables)
- 13.1 Всегда используйте
constилиletдля объявления переменных. Невыполнение этого требования приведет к созданию глобальных переменных. Мы хотим избежать загрязнения глобального пространства имен. Капитан Планета предупреждал нас об этом.
// bad
superPower = new SuperPower();
// good
const superPower = new SuperPower();
- 13.2 Используйте одно объявление
constилиletдля каждой переменной. eslint:one-varjscs:disallowMultipleVarDecl
Почему? Так легче добавлять новые объявления переменных, и вам никогда не придется беспокоиться о замене
;на,или внесении только разницы в пунктуации.
// bad
const items = getItems(),
goSportsTeam = true,
dragonball = 'z';
// bad
// (compare to above, notice the error)
const items = getItems(),
goSportsTeam = true;
dragonball = 'z';
// good
const items = getItems();
const goSportsTeam = true;
const dragonball = 'z';
- 13.3 Группируйте все
const, а затем всеlet.
Почему? Это полезно, когда позже вам может потребоваться присвоить переменную в зависимости от одной из ранее присвоенных переменных.
// bad
let i, len, dragonball,
items = getItems(),
goSportsTeam = true;
// bad
let i;
const items = getItems();
let dragonball;
const goSportsTeam = true;
let len;
// good
const goSportsTeam = true;
const items = getItems();
let dragonball;
let i;
let length;
- 13.4 Присваивайте переменные там, где они вам нужны, но размещайте их в разумном месте.
Почему?
letиconstимеют блочную область видимости (block scoped), а не функциональную (function scoped).
// bad - unnecessary function call
function checkName(hasName) {
const name = getName();
if (hasName === 'test') {
return false;
}
if (name === 'test') {
this.setName('');
return false;
}
return name;
}
// good
function checkName(hasName) {
if (hasName === 'test') {
return false;
}
const name = getName();
if (name === 'test') {
this.setName('');
return false;
}
return name;
}
Поднятие (Hoisting)
- 14.1 Объявления
varподнимаются наверх их области видимости, но их присваивание не поднимается. Объявленияconstиletблагословлены новой концепцией, называемой Временными мертвыми зонами (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 example() {
superPower(); // => Flying
function superPower() {
console.log('Flying');
}
}
- Для получения дополнительной информации см. JavaScript Scoping & Hoisting от Ben Cherry.
Операторы сравнения и равенства (Comparison Operators & Equality)
-
15.2 Условные операторы, такие как
if, оценивают свое выражение, используя приведение с помощью абстрактного методаToBoolean, и всегда следуют этим простым правилам:
- Objects оцениваются как true
- Undefined оценивается как false
- Null оценивается как false
- Booleans оцениваются как значение булева
- Numbers оцениваются как false, если +0, -0 или NaN, иначе true
- Strings оцениваются как false, если пустая строка
'', иначе true
if ([0] && []) {
// true
// массив (даже пустой) - это объект, объекты оцениваются как true
}
- 15.3 Используйте сокращения.
// bad
if (name !== '') {
// ...stuff...
}
// good
if (name) {
// ...stuff...
}
// bad
if (collection.length > 0) {
// ...stuff...
}
// good
if (collection.length) {
// ...stuff...
}
- 15.4 Для получения дополнительной информации см. Truth Equality and JavaScript от Angus Croll.
- 15.5 Используйте фигурные скобки для создания блоков в операторах
caseиdefault, которые содержат лексические объявления (например,let,const,functionиclass).
Почему? Лексические объявления видны во всем блоке switch, но инициализируются только при присваивании, что происходит только при достижении его
case. Это вызывает проблемы, когда несколькоcaseпытаются определить одно и то же.
eslint rules: no-case-declarations.
// bad
switch (foo) {
case 1:
let x = 1;
break;
case 2:
const y = 2;
break;
case 3:
function f() {}
break;
default:
class C {}
}
// good
switch (foo) {
case 1: {
let x = 1;
break;
}
case 2: {
const y = 2;
break;
}
case 3: {
function f() {}
break;
}
case 4:
bar();
break;
default: {
class C {}
}
}
- 15.7 Тернарные операторы не должны быть вложенными и, как правило, должны быть однострочными выражениями.
eslint rules: no-nested-ternary.
// bad
const foo = maybe1 > maybe2
? "bar"
: value1 > value2 ? "baz" : null;
// better
const maybeNull = value1 > value2 ? 'baz' : null;
const foo = maybe1 > maybe2
? 'bar'
: maybeNull;
// best
const maybeNull = value1 > value2 ? 'baz' : null;
const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
- 15.8 Избегайте ненужных тернарных операторов.
eslint rules: no-unneeded-ternary.
// bad
const foo = a ? a : b;
const bar = c ? true : false;
const baz = c ? false : true;
// good
const foo = a || b;
const bar = !!c;
const baz = !c;
Блоки (Blocks)
- 16.1 Используйте фигурные скобки со всеми многострочными блоками.
// bad
if (test)
return false;
// good
if (test) return false;
// good
if (test) {
return false;
}
// bad
function foo() { return false; }
// good
function bar() {
return false;
}
- 16.2 Если вы используете многострочные блоки с
ifиelse, поместитеelseна ту же строку, что и закрывающая фигурная скобка блокаif. eslint:brace-stylejscs:disallowNewlineBeforeBlockStatements
// bad
if (test) {
thing1();
thing2();
}
else {
thing3();
}
// good
if (test) {
thing1();
thing2();
} else {
thing3();
}
Управляющие конструкции (Control Statements)
- 17.1 Если ваша управляющая конструкция (
if,whileи т.д.) становится слишком длинной или превышает максимальную длину строки, каждое условие (сгруппированное) может быть помещено на новую строку. Логический оператор должен начинать строку.
Почему? Требование операторов в начале строки сохраняет выравнивание операторов и следует шаблону, похожему на цепочку методов. Это также улучшает читаемость, облегчая визуальное следование сложной логике.
// bad
if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
thing1();
}
// bad
if (foo === 123 &&
bar === 'abc') {
thing1();
}
// bad
if (foo === 123
&& bar === 'abc') {
thing1();
}
// bad
if (
foo === 123 &&
bar === 'abc'
) {
thing1();
}
// good
if (
foo === 123
&& bar === 'abc'
) {
thing1();
}
// good
if (
(foo === 123 || bar === 'abc')
&& doesItLookGoodWhenItBecomesThatLong()
&& isThisReallyHappening()
) {
thing1();
}
// good
if (foo === 123 && bar === 'abc') {
thing1();
}
- 17.2 Не используйте операторы выбора вместо управляющих конструкций.
// bad
!isRunning && startRunning();
// good
if (!isRunning) {
startRunning();
}
Комментарии (Comments)
- 18.1 Используйте
/** ... */для многострочных комментариев. Включите описание, укажите типы и значения для всех параметров и возвращаемых значений.
// bad
// make() returns a new element
// based on the passed in tag name
//
// @param {String} tag
// @return {Element} element
function make(tag) {
// ...stuff...
return element;
}
// good
/**
* make() returns a new element
* based on the passed in tag name
*
* @param {String} tag
* @return {Element} element
*/
function make(tag) {
// ...stuff...
return element;
}
- 18.2 Используйте
//для однострочных комментариев. Помещайте однострочные комментарии на новой строке над темой комментария. Оставьте пустую строку перед комментарием, если он не находится в первой строке блока.
// bad
const active = true; // is current tab
// good
// is current tab
const active = true;
// bad
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this._type || 'no type';
return type;
}
// good
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this._type || 'no type';
return type;
}
// also good
function getType() {
// set the default type to 'no type'
const type = this._type || 'no type';
return type;
}
-
18.3 Использование префиксов
FIXMEилиTODOв комментариях помогает другим разработчикам быстро понять, указываете ли вы на проблему, которую необходимо пересмотреть, или предлагаете решение, которое необходимо реализовать. Они отличаются от обычных комментариев тем, что они требуют действий. Действия:FIXME: -- need to figure this outилиTODO: -- need to implement. -
18.4 Используйте
// FIXME:для аннотирования проблем.
class Calculator extends Abacus {
constructor() {
super();
// FIXME: shouldn't use a global here
total = 0;
}
}
- 18.5 Используйте
// TODO:для аннотирования решений проблем.
class Calculator extends Abacus {
constructor() {
super();
// TODO: total should be configurable by an options param
this.total = 0;
}
}
Пробелы (Whitespace)
- 19.1 Используйте мягкие табы (пробелы), установленные на 2 пробела. eslint:
indentjscs:validateIndentation
// bad
function foo() {
∙∙∙∙const name;
}
// bad
function bar() {
∙const name;
}
// good
function baz() {
∙∙const name;
}
- 19.2 Поставьте 1 пробел перед открывающей фигурной скобкой. eslint:
space-before-blocksjscs:requireSpaceBeforeBlockStatements
// bad
function test(){
console.log('test');
}
// good
function test() {
console.log('test');
}
// bad
dog.set('attr',{
age: '1 year',
breed: 'Bernese Mountain Dog',
});
// good
dog.set('attr', {
age: '1 year',
breed: 'Bernese Mountain Dog',
});
- 19.3 Поставьте 1 пробел перед открывающей скобкой в управляющих конструкциях (
if,whileи т.д.). Не ставьте пробел между списком аргументов и именем функции в вызовах и объявлениях функций. eslint:space-after-keywords,space-before-keywordsjscs:requireSpaceAfterKeywords
// bad
if(isJedi) {
fight ();
}
// good
if (isJedi) {
fight();
}
// bad
function fight () {
console.log ('Swooosh!');
}
// good
function fight() {
console.log('Swooosh!');
}
- 19.4 Отделяйте операторы пробелами. eslint:
space-infix-opsjscs:requireSpaceBeforeBinaryOperators,requireSpaceAfterBinaryOperators
// bad
const x=y+5;
// good
const x = y + 5;
- 19.5 Заканчивайте файлы одним символом новой строки.
// bad
(function (global) {
// ...stuff...
})(this);
// bad
(function (global) {
// ...stuff...
})(this);↵
↵
// good
(function (global) {
// ...stuff...
})(this);↵
- 19.6 Используйте отступы при длинных цепочках методов (более 2 методов). Используйте точку в начале, чтобы подчеркнуть, что строка является вызовом метода, а не новой инструкцией. eslint:
newline-per-chained-callno-whitespace-before-property
// bad
$('#items').find('.selected').highlight().end().find('.open').updateCount();
// bad
$('#items').
find('.selected').
highlight().
end().
find('.open').
updateCount();
// good
$('#items')
.find('.selected')
.highlight()
.end()
.find('.open')
.updateCount();
// bad
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);
// good
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);
// good
const leds = stage.selectAll('.led').data(data);
- 19.7 Оставляйте пустую строку после блоков и перед следующей инструкцией. jscs:
requirePaddingNewLinesAfterBlocks
// bad
if (foo) {
return bar;
}
return baz;
// good
if (foo) {
return bar;
}
return baz;
// bad
const obj = {
foo() {
},
bar() {
},
};
return obj;
// good
const obj = {
foo() {
},
bar() {
},
};
return obj;
// bad
const arr = [
function foo() {
},
function bar() {
},
];
return arr;
// good
const arr = [
function foo() {
},
function bar() {
},
];
return arr;
- 19.8 Не заполняйте блоки пустыми строками. eslint:
padded-blocksjscs:disallowPaddingNewlinesInBlocks
// bad
function bar() {
console.log(foo);
}
// also bad
if (baz) {
console.log(qux);
} else {
console.log(foo);
}
// good
function bar() {
console.log(foo);
}
// good
if (baz) {
console.log(qux);
} else {
console.log(foo);
}
- 19.9 Не добавляйте пробелы внутри круглых скобок. eslint:
space-in-parensjscs:disallowSpacesInsideParentheses
// bad
function bar( foo ) {
return foo;
}
// good
function bar(foo) {
return foo;
}
// bad
if ( foo ) {
console.log(foo);
}
// good
if (foo) {
console.log(foo);
}
- 19.10 Не добавляйте пробелы внутри квадратных скобок. eslint:
array-bracket-spacingjscs:disallowSpacesInsideArrayBrackets
// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);
// good
const foo = [1, 2, 3];
console.log(foo[0]);
- 19.11 Добавляйте пробелы внутри фигурных скобок. eslint:
object-curly-spacingjscs: [disallowSpacesInsideObjectBrackets](http://jscs.info/rule/
// bad
const foo = {clark: 'kent'};
// good
const foo = { clark: 'kent' };
- 19.12 Избегайте строк длиннее 100 символов (включая пробелы). eslint:
max-lenjscs:maximumLineLength
Почему? Это обеспечивает читаемость и удобство сопровождения.
// bad
const foo = 'Whatever national crop flips the window. The cartoon reverts within the screw. Whatever wizard constrains a helpful ally. The counterpart ascends!';
// bad
$.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.'));
// good
const foo = 'Whatever national crop flips the window. The cartoon reverts within the screw. ' +
'Whatever wizard constrains a helpful ally. The counterpart ascends!';
// good
$.ajax({
method: 'POST',
url: 'https://airbnb.com/',
data: { name: 'John' },
})
.done(() => console.log('Congratulations!'))
.fail(() => console.log('You have failed this city.'));
Запятые (Commas)
- 20.1 Запятые в начале строки (Leading commas): Нет. eslint:
comma-stylejscs:requireCommaBeforeLineBreak
// bad
const story = [
once
, upon
, aTime
];
// good
const story = [
once,
upon,
aTime,
];
// bad
const hero = {
firstName: 'Ada'
, lastName: 'Lovelace'
, birthYear: 1815
, superPower: 'computers'
};
// good
const hero = {
firstName: 'Ada',
lastName: 'Lovelace',
birthYear: 1815,
superPower: 'computers',
};
- 20.2 Дополнительная висячая запятая (Additional trailing comma): Да. eslint:
comma-danglejscs:requireTrailingComma
Почему? Это приводит к более чистым git diff. Кроме того, транспиляторы, такие как Babel, будут удалять дополнительную висячую запятую в транспилированном коде, что означает, что вам не нужно беспокоиться о проблеме с висячей запятой в устаревших браузерах.
// bad - git diff without trailing comma
const hero = {
firstName: 'Florence',
lastName: 'Nightingale'
+ lastName: 'Nightingale',
+ inventorOf: ['coxcomb graph', 'modern nursing']
};
// good - git diff with trailing comma
const hero = {
firstName: 'Florence',
lastName: 'Nightingale',
+ inventorOf: ['coxcomb chart', 'modern nursing'],
};
// bad
const hero = {
firstName: 'Dana',
lastName: 'Scully'
};
const heroes = [
'Batman',
'Superman'
];
// good
const hero = {
firstName: 'Dana',
lastName: 'Scully',
};
const heroes = [
'Batman',
'Superman',
];
Точки с запятой (Semicolons)
- 21.1 Да. eslint:
semijscs:requireSemicolons
// bad
(function () {
const name = 'Skywalker'
return name
})()
// good
(() => {
const name = 'Skywalker';
return name;
}());
// good (guards against the function becoming an argument when two files with IIFEs are concatenated)
;(() => {
const name = 'Skywalker';
return name;
}());
Приведение типов и коэрцитивность (Type Casting & Coercion)
// => this.reviewScore = 9;
// bad
const totalScore = this.reviewScore + '';
// good
const totalScore = String(this.reviewScore);
- 22.3 Числа: Используйте
Numberдля приведения типов иparseIntвсегда с основанием для анализа строк. eslint:radix
const inputValue = '4';
// bad
const val = new Number(inputValue);
// bad
const val = +inputValue;
// bad
const val = inputValue >> 0;
// bad
const val = parseInt(inputValue);
// good
const val = Number(inputValue);
// good
const val = parseInt(inputValue, 10);
- 22.4 Если по какой-то причине вы делаете что-то безумное, и
parseIntявляется вашим узким местом, и вам нужно использовать Bitshift для соображений производительности, оставьте комментарий, объясняющий, почему и что вы делаете.
// good
/**
* parseInt was the reason my code was slow.
* Bitshifting the String to coerce it to a
* Number made it a lot faster.
*/
const val = inputValue >> 0;
- 22.5 Note: Будьте осторожны при использовании операций битового сдвига. Числа представлены как 64-битные значения, но операции битового сдвига всегда возвращают 32-битное целое число (источник). Битовый сдвиг может привести к неожиданному поведению для целочисленных значений больше 32 бит. Обсуждение. Самое большое 32-битное целое число со знаком — 2 147 483 647:
2147483647 >> 0 //=> 2147483647
2147483648 >> 0 //=> -2147483648
2147483649 >> 0 //=> -2147483647
- 22.6 Булевые значения:
const age = 0;
// bad
const hasAge = new Boolean(age);
// good
const hasAge = Boolean(age);
// good
const hasAge = !!age;
Соглашения об именовании (Naming Conventions)
- 23.1 Избегайте однобуквенных имен. Будьте описательны в своих именах.
// bad
function q() {
// ...stuff...
}
// good
function query() {
// ..stuff..
}
- 23.2 Используйте camelCase при именовании объектов, функций и экземпляров. eslint:
camelcasejscs:requireCamelCaseOrUpperCaseIdentifiers
// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}
// good
const thisIsMyObject = {};
function thisIsMyFunction() {}
- 23.3 Используйте PascalCase только при именовании конструкторов или классов. eslint:
new-capjscs:requireCapitalizedConstructors
// bad
function user(options) {
this.name = options.name;
}
const bad = new user({
name: 'nope',
});
// good
class User {
constructor(options) {
this.name = options.name;
}
}
const good = new User({
name: 'yup',
});
- 23.4 Используйте ведущее подчеркивание
_при именовании приватных свойств. eslint:no-underscore-danglejscs:disallowDanglingUnderscores
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
// good
this._firstName = 'Panda';
- 23.5 Не сохраняйте ссылки на
this. Используйте стрелочные функции или Function#bind. jscs:disallowNodeTypes
// bad
function foo() {
const self = this;
return function () {
console.log(self);
};
}
// bad
function foo() {
const that = this;
return function () {
console.log(that);
};
}
// good
function foo() {
return () => {
console.log(this);
};
}
- 23.6 Если ваш файл экспортирует один класс, имя вашего файла должно точно совпадать с именем вашего класса.
// file contents
class CheckBox {
// ...
}
export default CheckBox;
// in some other file
// bad
import CheckBox from './checkBox';
// bad
import CheckBox from './check_box';
// good
import CheckBox from './CheckBox';
- 23.7 Используйте camelCase при экспорте функции по умолчанию. Имя вашего файла должно быть идентичным имени вашей функции.
function makeStyleGuide() {
}
export default makeStyleGuide;
- 23.8 Используйте PascalCase при экспорте синглтона / библиотеки функций / пустого объекта.
const AirbnbStyleGuide = {
es6: {
}
};
export default AirbnbStyleGuide;
Аксессоры (Accessors)
- 24.1 Функции доступа для свойств не обязательны.
- 24.2 Не используйте геттеры/сеттеры JavaScript, так как они вызывают неожиданные побочные эффекты и их сложнее тестировать, поддерживать и понимать. Вместо этого, если вы создаете функции доступа, используйте getVal() и setVal(‘hello’).
// bad
dragon.age();
// good
dragon.getAge();
// bad
dragon.age(25);
// good
dragon.setAge(25);
- 24.3 Если свойство является логическим, используйте
isVal()илиhasVal().
// bad
if (!dragon.age()) {
return false;
}
// good
if (!dragon.hasAge()) {
return false;
}
- 24.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];
}
}
События (Events)
- 25.1 При присоединении полезных данных к событиям (будь то события DOM или что-то более проприетарное, например, события Backbone), передавайте хэш вместо необработанного значения. Это позволяет последующему участнику добавлять больше данных в полезную нагрузку события без поиска и обновления каждого обработчика для события. Например, вместо:
// bad
$(this).trigger('listingUpdated', listing.id);
...
$(this).on('listingUpdated', (e, listingId) => {
// do something with listingId
});
предпочитайте:
// good
$(this).trigger('listingUpdated', { listingId: listing.id });
...
$(this).on('listingUpdated', (e, data) => {
// do something with data.listingId
});
jQuery
- 26.1 Добавляйте к объектам jQuery префикс
$. jscs:requireDollarBeforejQueryAssignment
// bad
const sidebar = $('.sidebar');
// good
const $sidebar = $('.sidebar');
// good
const $sidebarBtn = $('.sidebar-btn');
- 26.2 Кэшируйте выборки jQuery.
// bad
function setSidebar() {
$('.sidebar').hide();
// ...stuff...
$('.sidebar').css({
'background-color': 'pink'
});
}
// good
function setSidebar() {
const $sidebar = $('.sidebar');
$sidebar.hide();
// ...stuff...
$sidebar.css({
'background-color': 'pink'
});
}
- 26.3 Для запросов DOM используйте каскадный
$('.sidebar ul')или parent > child$('.sidebar > ul'). jsPerf - 26.4 Используйте
findс запросами к объекту jQuery с областью видимости.
// bad
$('ul', '.sidebar').hide();
// bad
$('.sidebar').find('ul').hide();
// good
$('.sidebar ul').hide();
// good
$('.sidebar > ul').hide();
// good
$sidebar.find('ul').hide();
Совместимость с ECMAScript 5 (ECMAScript 5 Compatibility)
- 27.1 Обратитесь к таблице совместимости ES5 от Kangax.
Стили ECMAScript 6 (ECMAScript 6 Styles)
- 28.1 Это коллекция ссылок на различные функции ES6.
- Arrow Functions
- Classes
- Object Shorthand
- Object Concise
- Computed Object Properties
- Template Strings
- Destructuring
- Default Parameters
- Rest
- Array Spreads
- Let and Const
- Iterators and Generators
- Modules
Стандартная библиотека (Standard Library)
Стандартная библиотека содержит утилиты, которые сломаны, но сохранены по соображениям наследия.
- 29.1 Используйте
Number.isNaNвместоisNaN.
Почему?
isNaNприводит нечисловые значения к числам, возвращая true для всего, что приводится к NaN. Если такое поведение желательно, сделайте его явным.
// bad
isNaN('1.2'); // false
isNaN('1.2.3'); // true
// good
Number.isNaN('1.2.3'); // false
Number.isNaN(Number('1.2.3')); // true
- 29.2 Используйте
Number.isFiniteвместоisFinite.
Почему?
isFiniteприводит нечисловые значения к числам, возвращая true для всего, что приводится к конечному числу. Если такое поведение желательно, сделайте его явным.
// bad
isFinite('2e3'); // true
// good
Number.isFinite('2e3'); // false
Number.isFinite(parseInt('2e3', 10)); // true
Тестирование (Testing)
- 30.1 Да.
function foo() {
return true;
}
- 30.2 Нет, серьезно:
- Какой бы фреймворк для тестирования вы ни использовали, вы должны писать тесты!
- Старайтесь писать много маленьких чистых функций и минимизируйте места, где происходят изменения.
- Будьте осторожны с заглушками и моками — они могут сделать ваши тесты более хрупкими.
- Мы в основном используем
mochaв Airbnb.tapeтакже иногда используется для небольших, отдельных модулей. - 100% покрытие тестами — хорошая цель, к которой нужно стремиться, даже если ее не всегда практично достичь.
- Каждый раз, когда вы исправляете ошибку, пишите регрессионный тест. Ошибка, исправленная без регрессионного теста, почти наверняка сломается снова в будущем.
Производительность (Performance)
- On Layout & Web Performance
- String vs Array Concat
- Try/Catch Cost In a Loop
- Bang Function
- jQuery Find vs Context, Selector
- innerHTML vs textContent for script text
- Long String Concatenation
- Loading…
Ресурсы (Resources)
Изучайте ES6
- Draft ECMA 2015 (ES6) Spec
- ExploringJS
- ES6 Compatibility Table
- Comprehensive Overview of ES6 Features
Прочтите это
Инструменты
- Code Style Linters
Другие руководства по стилю
- Google JavaScript Style Guide
- jQuery Core Style Guidelines
- Principles of Writing Consistent, Idiomatic JavaScript
Другие стили
- Naming this in nested functions - Christian Johansen
- Conditional Callbacks - Ross Allen
- Popular JavaScript Coding Conventions on Github - JeongHoon Byun
- Multiple var statements in JavaScript, not superfluous - Ben Alman
Дополнительная литература
- Understanding JavaScript Closures - Angus Croll
- Basic JavaScript for the impatient programmer - Dr. Axel Rauschmayer
- You Might Not Need jQuery - Zack Bloom & Adam Schwartz
- ES6 Features - Luke Hoban
- Frontend Guidelines - Benjamin De Cock
Книги
- JavaScript: The Good Parts - Douglas Crockford
- JavaScript Patterns - Stoyan Stefanov
- Pro JavaScript Design Patterns - Ross Harmes and Dustin Diaz
- High Performance Web Sites: Essential Knowledge for Front-End Engineers - Steve Souders
- Maintainable JavaScript - Nicholas C. Zakas
- JavaScript Web Applications - Alex MacCaw
- Pro JavaScript Techniques - John Resig
- Smashing Node.js: JavaScript Everywhere - Guillermo Rauch
- Secrets of the JavaScript Ninja - John Resig and Bear Bibeault
- Human JavaScript - Henrik Joreteg
- Superhero.js - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
- JSBooks - Julien Bouquillon
- Third Party JavaScript - Ben Vinegar and Anton Kovalyov
- Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript - David Herman
- Eloquent JavaScript - Marijn Haverbeke
- You Don’t Know JS: ES6 & Beyond - Kyle Simpson
Блоги
- DailyJS
- JavaScript Weekly
- JavaScript, JavaScript…
- Bocoup Weblog
- Adequately Good
- NCZOnline
- Perfection Kills
- Ben Alman
- Dmitry Baranovskiy
- Dustin Diaz
- nettuts
Подкасты
В дикой природе (In the Wild)
Это список организаций, которые используют это руководство по стилю. Отправьте нам пул-реквест или откройте issue, и мы добавим вас в список.
- Aan Zee: AanZee/javascript
- Adult Swim: adult-swim/javascript
- Airbnb: airbnb/javascript
- Apartmint: apartmint/javascript
- Avalara: avalara/javascript
- Avant: avantcredit/javascript
- Billabong: billabong/javascript
- Bisk: bisk/javascript
- Blendle: blendle/javascript
- Brainshark: brainshark/javascript
- ComparaOnline: comparaonline/javascript
- Compass Learning: compasslearning/javascript-style-guide
- DailyMotion: dailymotion/javascript
- Digitpaint digitpaint/javascript
- Ecosia: ecosia/javascript
- Evernote: evernote/javascript-style-guide
- Evolution Gaming: evolution-gaming/javascript
- ExactTarget: ExactTarget/javascript
- Expensify Expensify/Style-Guide
- Flexberry: Flexberry/javascript-style-guide
- Gawker Media: gawkermedia/javascript
- General Electric: GeneralElectric/javascript
- GoodData: gooddata/gdc-js-style
- Grooveshark: grooveshark/javascript
- How About We: howaboutwe/javascript
- Huballin: huballin/javascript
- HubSpot: HubSpot/javascript
- Hyper: hyperoslo/javascript-playbook
- InfoJobs: InfoJobs/JavaScript-Style-Guide
- Intent Media: intentmedia/javascript
- Jam3: Jam3/Javascript-Code-Conventions
- JeopardyBot: kesne/jeopardy-bot
- JSSolutions: JSSolutions/javascript
- Kinetica Solutions: kinetica/javascript
- Mighty Spring: mightyspring/javascript
- MinnPost: MinnPost/javascript
- MitocGroup: MitocGroup/javascript
- ModCloth: modcloth/javascript
- Money Advice Service: moneyadviceservice/javascript
- Muber: muber/javascript
- National Geographic: natgeo/javascript
- National Park Service: nationalparkservice/javascript
- Nimbl3: nimbl3/javascript
- Orion Health: orionhealth/javascript
- OutBoxSoft: OutBoxSoft/javascript
- Peerby: Peerby/javascript
- Razorfish: razorfish/javascript-style-guide
- reddit: reddit/styleguide/javascript
- React: /facebook/react/blob/master/CONTRIBUTING.md#style-guide
- REI: reidev/js-style-guide
- Ripple: ripple/javascript-style-guide
- SeekingAlpha: seekingalpha/javascript-style-guide
- Shutterfly: shutterfly/javascript
- Springload: springload/javascript
- StudentSphere: studentsphere/javascript
- Target: target/javascript
- TheLadders: TheLadders/javascript
- T4R Technology: T4R-Technology/javascript
- VoxFeed: VoxFeed/javascript-style-guide
- WeBox Studio: weboxstudio/javascript
- Weggo: Weggo/javascript
- Zillow: zillow/javascript
- ZocDoc: ZocDoc/javascript
Перевод (Translation)
Это руководство по стилю также доступно на других языках:
Brazilian Portuguese: armoucar/javascript-style-guide
Bulgarian: borislavvv/javascript
Catalan: fpmweb/javascript-style-guide
Chinese (Simplified): sivan/javascript-style-guide
Chinese (Traditional): jigsawye/javascript
French: nmussy/javascript-style-guide
German: timofurrer/javascript-style-guide
Italian: sinkswim/javascript-style-guide
Japanese: mitsuruog/javacript-style-guide
Korean: tipjs/javascript-style-guide
Polish: mjurczyk/javascript
Russian: uprock/javascript
Spanish: paolocarrasco/javascript-style-guide
Vietnamese: f1remoon/javascript-style-guide
Руководство по Руководству по стилю JavaScript (The JavaScript Style Guide Guide)
Общайтесь с нами о JavaScript
- Найдите нас на gitter.
Участники (Contributors)
Лицензия (License)
(The MIT License)
Copyright (c) 2014-2016 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.
Поправки (Amendments)
Мы рекомендуем вам создать форк этого руководства и изменить правила в соответствии с стилем вашей команды. Ниже вы можете перечислить некоторые поправки к руководству по стилю. Это позволяет вам периодически обновлять руководство по стилю без необходимости разрешать конфликты слияния (merge conflicts).