- Кодировка UTF-8
- Перевод строки: LF. В конце файла перевод строки обязателен.
- Отступ 2 пробела, знаки табуляции не применяются.
- Длина линии не должна превышать 120 символов.
- Нет лишних пробелов в конце строк (настраиваем свой текстовый редактор, чтобы он удалял лишние пробелы при сохранении).
.editorconfig
берем из этого репозитория
variable_names_like_this
$jquery_variable_names_like_this
functionNamesLikeThis
ClassNamesLikeThis
methodNamesLikeThis
CONSTANTS_LIKE_THIS
event-like-this:event-logic-namespace
private
свойства и методы объектов начинаются с подчеркивания_
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;
});