- Кодировка UTF-8
- Перевод строки: LF. В конце файла перевод строки обязателен.
- Отступ 2 пробела, знаки табуляции не применяются.
- Длина линии не должна превышать 120 символов.
- Нет лишних пробелов в конце строк (настраиваем свой текстовый редактор, чтобы он удалял лишние пробелы при сохранении).
.editorconfigберем из этого репозитория
variable_names_like_this$jquery_variable_names_like_thisfunctionNamesLikeThisClassNamesLikeThismethodNamesLikeThisCONSTANTS_LIKE_THISevent-like-this:event-logic-namespaceprivateсвойства и методы объектов начинаются с подчеркивания_protectedсвойства и методы объектов также начинаются с подчеркивания_- Избегаем коротких или немногословных названий
- Переменные объявляются в одном блоке
varв начале функции/метода и т.п. - Каждая переменная в пределах одной области видимости объявляется только один раз.
- Каждая переменная объявляется на новой строке. Это позволяет легко менять строки местами и подписывать к ним комментарии.
Хорошо:
var keys = ['foo', 'bar'],
values = [23, 42],
object = {},
key;
while (items.length) {
key = keys.pop();
object[key] = values.pop();
}Плохо:
var keys = ['foo', 'bar'];
var values = [23, 42];
var object = {};
while (items.length) {
var key = keys.pop();
object[key] = values.pop();
}- После открывающей фигурной скобки и перед закрывающей пробел не ставится:
var obj = {a: 1, b: 2, c: 3};
this.method({a: 1, b: 2});- Пробел перед двоеточием не ставится:
var obj = {
prop: 0
};- Выравнивание не используется:
Хорошо:
var obj = {
a: 0,
b: 1,
lengthy_name: 2
};Плохо:
var obj = {
a : 0,
b : 1,
lengthy_name: 2
};- Имена ключей заключаются в кавычки только по необходимости:
Хорошо:
var obj = {
key: 0,
'key-key': 1
};Плохо:
var obj = {
'key': 0,
'key-key': 1
};При объявлении массива, пробел ставится лишь после запятой:
var fellowship = ['foo', 'bar', 'baz'];- Строки записываются с использованием одинарных кавычек:
var lyrics = 'Never gonna give you up, Never gonna let you down';- Если в строке встречается одинарная кавычка, она экранируется:
var test = 'It shouldn\'t fail';Точка с запятой ставится всегда.
- Ключевые слова отделяются пробелом:
if (test) {
// ...
}
function foo() {
// ...
}
var bar = function () {
// ...
};- Перед точкой с запятой пробел не ставится:
return;- Открывающая фигурная скобка ставится на той же строке и отделяется пробелом от предыдущей конструкции:
if (test) {
// ...
}
function foo() {
// ...
}- Фигурные скобки ставятся всегда:
Хорошо:
if (test) {
return;
}Плохо:
if (test)
return;
if (test) return;
if (test) { return; }elseпишется на той же строке, что и закрывающая фигурная скобка
if (test) {
// ...
} else {
// ...
}- Присваивание в условном выражении не используется:
Хорошо:
var foo = bar();
if (foo > 0) {
// ...
}Плохо:
var foo;
if ((foo = bar()) > 0) {
// ...
}- Выражения используются только там, где требуется значение:
Хорошо:
if (condition) {
actionIfTrue();
} else {
actionIfFalse();
}Плохо:
condition && actionIfTrue() || actionIfFalse();- Длинные условия, которые не вмещаются на одну строку, разбиваются следующим образом:
if (longCondition ||
anotherLongCondition &&
yetAnotherLongCondition
) {
// ...
}- Yoda conditions не используются:
Хорошо:
if (getType() === 'driving') {
}Плохо:
if ('driving' === getType()) {
}switch (value) {
case 1:
// ...
break;
case 2:
// ...
break;
default:
// ...
// no break keyword on the last case
}По возможности вместо for используется Array.prototype.forEach:
[1, 2, 3].forEach(function (value) {
console.log(value);
});Код с использованием forEach проще читать (легче абстрагироваться от того, что происходит в каждой итерации). Где
критична скорость используется обычный for.
По возможности вместо for-in используется Object.keys:
Object.keys(obj).forEach(function (key) {
console.log(key);
});Оператор with не используется.
Всегда используется строгое равенство === (неравенство !==), если нет необходимости в приведении типов.
var x = a ? b : c;
var y = a ?
longButSimpleOperandB : longButSimpleOperandC;
var z = a ?
moreComplicatedB :
moreComplicatedC;Все унарные операторы пишутся слитно с операндами:
var foo = !bar;Избегаем использования eval. Для парсинга json используется JSON.parse.
Проверяем значение через строгое сравнение.
Хорошо:
x === undefined;Плохо:
// в современных браузерах уже определен immutable undefined.
var undefined;
x === undefined;
// больше писать
typeof x === 'undefined'
x === void 0- Ставятся, если только это необходимо синтаксисом или семантикой.
- Не используются с унарными операторами
delete,typeofиvoid, а также ключевыми словамиreturn,throw,new.
Создаём исключения с помощью new Error:
Хорошо:
throw new Error('msg');Плохо:
throw 'msg';Используются явные приведения типов:
Хорошо:
Boolean(foo)
Number(bar)
String(baz)
[].indexOf(qux) === -1 или [].indexOf(qux) < 0Плохо:
!!foo
+bar
baz + ''
~[].indexOf(qux)- Максимальная длина строки
120символов, если строка выходит длиннее, то по возможности делаются переносы строки, с соответствующими отступами после переноса. - Операторы размещаются на предыдущей строке:
var debt = this.calculateBaseDebt() + this.calculateSharedDebt() + this.calculateDebtPayments() +
this.calculateDebtFine();- Закрывающие скобки не прижимаются к переносимому коду:
Хорошо:
DoSomethingThatRequiresALongFunctionName(
very_long_argument1,
argument2,
argument3,
argument4
);
anotherStatement;Плохо:
DoSomethingThatRequiresALongFunctionName(
very_long_argument1,
argument2,
argument3,
argument4);
anotherStatement;- Для конкатенации строк используется оператор
+. - Конструкция
[].join('')не используется (это было актуально для старых браузеров). \не используется.
Хорошо:
var foo = 'A rather long string of English text, an error message ' +
'actually that just keeps going and going -- an error ' +
'message to make the Energizer bunny blush (right through ' +
'those Schwarzenegger shades)! Where was I? Oh yes, ' +
'you\'ve got an error and all the extraneous whitespace is ' +
'just gravy. Have a nice day.';Плохо:
var foo = 'A rather long string of English text, an error message \
actually that just keeps going and going -- an error \
message to make the Energizer bunny blush (right through \
those Schwarzenegger shades)! Where was I? Oh yes, \
you\'ve got an error and all the extraneous whitespace is \
just gravy. Have a nice day.';Могут использоваться для логической группировки частей кода:
doSomethingTo(x);
doSomethingElseTo(x);
andThen(x);
nowDoSomethingWith(y);
andNowWith(z);- Рекомендуется использовать
Function.prototype.bindили, там где используется underscore -_.bind:
doAsync(function () {
this.fn();
}.bind(this));- Если функция позволяет передать
thisпараметром, используем его:
Хорошо:
[1, 2, 3].forEach(function (n) {
this.fn(n);
}, this);Плохо:
[1, 2, 3].forEach(function (n) {
this.fn(n);
}.bind(this));- Если используется переменная, называем ее
_this:
var _this = this;
doAsync(function () {
_this.fn();
});- Комментарии пишутся на русском языке.
- Для инлайновых комментариев используется
//. После//ставится 1 пробел. - Комментарии к функциям, классам и т.п. пишутся в формате jsdoc.
Выбирая сигнатуру функции, необходимо избегать Boolean Trap:
/**
* @param {Boolean} async
*/
function fetchResults(async) {}
// По вызову функции непонятно, что означает false.
fetchResults(false);Используем следующие методы для того, чтобы избежать Boolean Trap:
- Создаем функции-обертки для
fetchResults:
function fetchResultsSync() {}
function fetchResultsAsync() {}- Использовать константы, перечисления или статические поля классов для значений параметров;
/**
* @enum {Boolean}
*/
var FetchMethod = {
SYNC: false,
ASYNC: true
};
/**
* @param {FetchMethod} method
*/
function fetchResults(method) {}
fetchResults(FetchMethod.SYNC);Так же избегаем Convinience Trap:
// Пример из WebGL (предлагается угадать без документации, что каждое число и false означают)
glCtx.vertexAttribPointer(this._glHandler, 4, glCtx.FLOAT, false, 0, 0);От Convinience Trap и Boolean Trap необходимо использовать именованные параметры:
/**
* @param {Object} params
* @param {Boolean} params.async
*/
function fetchResults(params) {}
fetchResults({async: false});
glCtx.vertexAttribPointer(this._glHandler, {
size: 4,
type: glCtx.FLOAT,
normalizeData: false,
stride: 0,
offset: 0
});- Всегда используем
'use strict';в верху объявления модуля
define(function (require) {
'use strict';
var $ = require('jquery'), // just for example
fn = {};
fn.sum = function (a, b) {
return a + b;
};
return fn;
});