Наиболее разумный подход к JavaScript
Основано на airbnb/javascript.
- Типы
- Объекты
- Массивы
- Строки
- Функции
- Свойства
- Переменные
- Области видимости
- Условные выражения и равенства
- Блоки кода
- Комментарии
- Синтаксис
- Пробелы
- Запятые
- Точки с запятой
- Приведение типов
- Соглашение об именовании
- Геттеры и сеттеры
- Конструкторы
- События
- Модули
- jQuery
- Зависимости
- Совместимость с ES5
- Тестирование
- Быстродействие
- Ресурсы
-
Простые типы: Когда вы взаимодействуете с простым типом, вы взаимодействуете непосредственно с его значением в памяти.
string
number
boolean
null
undefined
var foo = 1, bar = foo; bar = 9; console.log(foo, bar); // => 1, 9. foo не изменился
-
Сложные типы: Когда вы взаимодействуете со сложным типом, вы взаимодействуете с ссылкой на его значение в памяти.
object
array
function
var foo = [1, 2], bar = foo; bar[0] = 9; console.log(foo[0], bar[0]); // => 9, 9.
-
Для создания объекта используйте фигурные скобки. Не создавайте объекты через конструктор
new Object
.// плохо var item = new Object(); // хорошо var item = {};
-
Не используйте зарезервированные слова в качестве ключей объектов. Они не будут работать в IE8. Подробнее
// плохо var superman = { default: { clark: "kent" }, private: true }; // хорошо var superman = { defaults: { clark: "kent" }, hidden: true };
-
Не используйте ключевые слова (в том числе измененные). Вместо них используйте синонимы.
// плохо var superman = { class: "alien" }; // плохо var superman = { klass: "alien" }; // хорошо var superman = { type: "alien" };
-
Для создания массива используйте квадратные скобки. Не создавайте массивы через конструктор
new Array
.// плохо var items = new Array(); // хорошо var items = [];
-
Если вы не знаете длину массива, используйте Array::push.
var someStack = [];
// плохо someStack[someStack.length] = 'csssr';
// хорошо someStack.push('csssr');
-
Если вам необходимо скопировать массив, используйте Array::slice. jsPerf
var len = items.length, itemsCopy = [], i; // плохо for (i = 0; i < len; i++) { itemsCopy[i] = items[i]; } // хорошо itemsCopy = items.slice();
-
Чтобы скопировать похожий по свойствам на массив объект (например, NodeList или Arguments), используйте Array::slice.
function trigger() { var args = Array.prototype.slice.call(arguments); ... }
-
Используйте одинарные кавычки
''
для строк.// плохо var name = "Боб Дилан"; // хорошо var name = "Боб Дилан"; // плохо var fullName = "Боб " + this.lastName; // хорошо var fullName = "Дилан " + this.lastName;
-
Строки длиннее 80 символов нужно разделять, выполняя перенос через конкатенацию строк.
-
Осторожно: строки с большим количеством конкатенаций могут отрицательно влиять на быстродействие. jsPerf и Обсуждение
// плохо var errorMessage = "Эта сверхдлинная ошибка возникла из-за белой обезъяны. Не говори про обезъяну! Не слушай об обезьяне! Не думай об обезъяне!"; // плохо var errorMessage = "Эта сверхдлинная ошибка возникла из-за белой обезъяны. \
Не говори про обезъяну! Не слушай об обезьяне!
Не думай об обезъяне!";
// хорошо var errorMessage = "Эта сверхдлинная ошибка возникла из-за белой обезъяны. " + "Не говори про обезъяну! Не слушай об обезьяне! " + "Не думай об обезъяне!";
* Когда строка создается программным путем, используйте Array::join вместо объединения строк. В основном для IE: [jsPerf](http://jsperf.com/string-vs-array-concat/2).
```javascript
var items, messages, length, i;
messages = [
{
state: "success",
message: "Это работает."
},
{
state: "success",
message: "Это тоже."
},
{
state: "error",
message: "А я томат."
}
];
length = messages.length;
// плохо
function inbox(messages) {
items = "<ul>";
for (i = 0; i < length; i++) {
items += "<li>" + messages[i].message + "</li>";
}
return items + "</ul>";
}
// хорошо
function inbox(messages) {
items = [];
for (i = 0; i < length; i++) {
items[i] = messages[i].message;
}
return "<ul><li>" + items.join("</li><li>") + "</li></ul>";
}
-
Объявление функций:
// объявление анонимной функции var anonymous = function() { return true; }; // объявление именованной функции var named = function named() { return true; }; // объявление функции, которая сразу же выполняется (замыкание) (function() { console.log("Если вы читаете это, вы открыли консоль."); })();
-
Никогда не объявляйте функцию внутри блока кода — например в if, while, else и так далее. Единственное исключение — блок функции. Вместо этого присваивайте функцию уже объявленной через
var
переменной. Условное объявление функций работает, но в различных браузерах работает по-разному. -
Примечание ECMA-262 устанавливает понятие
блока
как списка операторов. Объявление функции (не путайте с присвоением функции переменной) не является оператором. Комментарий по этому вопросу в ECMA-262.// плохо if (currentUser) { function test() { console.log("Плохой мальчик."); } } // хорошо var test; if (currentUser) { test = function test() { console.log("Молодец."); }; }
-
Никогда не используйте аргумент функции
arguments
, он будет более приоритетным над объектомarguments
, который доступен без объявления для каждой функции.// плохо function nope(name, options, arguments) { // ...код... } // хорошо function yup(name, options, args) { // ...код... }
-
Используйте точечную нотацию для доступа к свойствам и методам.
var luke = { jedi: true, age: 28 }; // плохо var isJedi = luke["jedi"]; // хорошо var isJedi = luke.jedi;
-
Используйте нотацию с
[]
, когда вы получаете свойство, имя для которого хранится в переменной.var luke = { jedi: true, age: 28 }; function getProp(prop) { return luke[prop]; } var isJedi = getProp("jedi");
-
Всегда используйте
var
для объявления переменных. В противном случае переменная будет объявлена глобальной. Загрязнение глобального пространства имен — всегда плохо.// плохо superPower = new SuperPower(); // хорошо var superPower = new SuperPower();
-
Используйте одно
var
объявление переменных для всех переменных, и объявляйте каждую переменную на новой строке.// плохо var items = getItems(); var goSportsTeam = true; var dragonball = "z"; // хорошо var items = getItems(), goSportsTeam = true, dragonball = "z";
-
Объявляйте переменные, которым не присваивается значение, в конце. Это удобно, когда вам необходимо задать значение одной из этих переменных на базе уже присвоенных значений.
// плохо var i, len, dragonball, items = getItems(), goSportsTeam = true; // плохо var i, items = getItems(), dragonball, goSportsTeam = true, len; // хорошо var items = getItems(), goSportsTeam = true, dragonball, length, i;
-
Присваивайте переменные в начале области видимости. Это помогает избегать проблем с объявлением переменных и областями видимости.
// плохо function () { test(); console.log('Делаю что-нибудь..'); //..или не делаю... var name = getName(); if (name === 'test') { return false; } return name; } // хорошо function() { var name = getName(); test(); console.log('Делаю что-то полезное..'); //..продолжаю приносить пользу людям.. if (name === 'test') { return false; } return name; } // плохо function() { var name = getName(); if (!arguments.length) { return false; } return true; } // хорошо function() { if (!arguments.length) { return false; } var name = getName(); return true; }
-
Объявление переменных ограничивается областью видимости, а присвоение — нет.
// Мы знаем, что это не будет работать // если нет глобальной переменной notDefined function example() { console.log(notDefined); // => выбрасывает код с ошибкой ReferenceError } // Декларирование переменной после ссылки на нее // не будет работать из-за ограничения области видимости. function example() { console.log(declaredButNotAssigned); // => undefined var declaredButNotAssigned = true; } // Интерпретатор переносит объявление переменной // к верху области видимости. // Что значит, что предыдущий пример в действительности // будет воспринят интерпретатором так: function example() { var declaredButNotAssigned; console.log(declaredButNotAssigned); // => undefined declaredButNotAssigned = true; }
-
Объявление анонимной функции поднимает наверх области видимости саму переменную, но не ее значение.
function example() { console.log(anonymous); // => undefined anonymous(); // => TypeError anonymous is not a function // Ошибка типов: переменная anonymous не является функцией и не может быть вызвана var anonymous = function() { console.log("анонимная функция"); }; }
-
Именованные функции поднимают наверх области видимости переменную, не ее значение. Имя функции при этом недоступно в области видимости переменной и доступно только изнутри.
function example() { console.log(named); // => undefined named(); // => TypeError named is not a function // Ошибка типов: переменная named не является функцией и не может быть вызвана superPower(); // => ReferenceError superPower is not defined (Ошибка ссылки: переменная superPower не найдена в этой области видимости) var named = function superPower() { console.log("Я лечууууу"); }; } // То же самое происходит, когда имя функции и имя переменной совпадают. // var named доступно изнутри области видимости функции example. // function named доступна только изнутри ее самой. function example() { console.log(named); // => undefined named(); // => TypeError named is not a function // Ошибка типов: переменная named не является функцией и не может быть вызвана var named = function named() { console.log("именованная функция"); }; }
-
Объявления функции поднимают на верх текущей области видимости и имя, и свое значение.
function example() { superPower(); // => Я лечууууу function superPower() { console.log("Я лечууууу"); } }
-
Более подробно можно прочитать в статье JavaScript Scoping & Hoisting от Ben Cherry
-
Используйте
===
и!==
вместо==
и!=
. -
Условные выражения вычисляются посредством приведения к логическому типу Boolean через метод
ToBoolean
и всегда следуют следующим правилам:- Object всегда соответствует true
- Undefined всегда соответствует false
- Null всегда соответствует false
- Boolean остается неизменным
- Number соответствует false, если является +0, -0, или NaN, в противном случае соответствует true
- String означает false, если является пустой строкой
''
, в противном случае true. Условно говоря, для строки происходит сравнение не ее самой, а ее длины – в соответствии с типом number.
if ([0]) { // true // Массив(Array) является объектом, объекты преобразуются в true }
-
Используйте короткий синтаксис.
// плохо if (name !== "") { // ...код... } // хорошо if (name) { // ...код... } // плохо if (collection.length > 0) { // ...код... } // хорошо if (collection.length) { // ...код... }
-
Более подробно можно прочитать в статье Truth Equality and JavaScript от Angus Croll
-
Используйте фигурные скобки для всех многострочных блоков.
// плохо if (test) return false; // хорошо if (test) return false; // хорошо if (test) { return false; } // плохо function() { return false; } // хорошо function() { return false; }
-
Используйте
/** ... */
для многострочных комментариев. Включите описание, опишите типы и значения для всех параметров и возвращаемых значений в формате jsdoc.// плохо // make() возвращает новый элемент // основываясь на получаемом имени тэга // // @param <String> tag // @return <Element> element function make(tag) { // ...создаем element... return element; } // хорошо /** * make() возвращает новый элемент * основываясь на получаемом имени тэга * * @param <String> tag * @return <Element> element */ function make(tag) { // ...создаем element... return element; }
-
Используйте
//
для комментариев в одну строку. Размещайте комментарии на новой строке над темой комментария. Добавляйте пустую строку над комментарием.// плохо var active = true; // устанавливаем активным элементом // хорошо // устанавливаем активным элементом var active = true; // плохо function getType() { console.log("проверяем тип..."); // задаем тип по умолчанию 'no type' var type = this._type || "no type"; return type; } // хорошо function getType() { console.log("проверяем тип..."); // задаем тип по умолчанию 'no type' var type = this._type || "no type"; return type; }
-
Префикс
TODO
помогает другим разработчикам быстро понять, что вы указываете на проблему, к которой нужно вернуться в дальнейшем, или если вы предлагете решение проблемы, которое должно быть реализовано. Эти комментарии отличаются от обычных комментариев, так как не описывают текущее поведение, а призывают к действию, напримерTODO -- нужно реализовать интерфейс
. Такие комментарии также автоматически обнаруживаются многими IDE и редакторами кода, что позволяет быстро перемещаться между ними. -
Используйте
// TODO FIXME:
для аннотирования проблемfunction Calculator() { // TODO FIXME: тут не нужно использовать глобальную переменную total = 0; return this; }
-
Используйте
// TODO:
для указания решений проблемfunction Calculator() { // TODO: должна быть возможность изменять значение через параметр функции this.total = 0; return this; }
**[[⬆]](#Оглавление)**
## <a name='syntax'>Синтаксис</a>
![javascript-syntax](https://cloud.githubusercontent.com/assets/2854701/3838799/c95fadf4-1e08-11e4-9a61-54a05120db35.png)
## <a name='whitespace'>Пробелы</a>
- Используйте табуляцию вместо пробелов, т.к. размер можно настроить на своё усмотрение в любом редакторе кода (размер табуляции по умолчанию 4).
```javascript
// плохо
function() {
∙var name;
}
// плохо
function() {
∙∙var name;
}
// плохо
function() {
∙∙∙∙var name;
}
// хорошо
function() {
var name;
}
```
- Устанавливайте один пробел перед открывающей скобкой.
```javascript
// плохо
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'
});
```
- Оставляйте новую строку в конце файла.
```javascript
// плохо
(function (global) {
// ...код...
})(this);
```
```javascript
// хорошо
(function (global) {
// ...код...
})(this);
```
- Используйте отступы, когда делаете цепочки вызовов.
```javascript
// плохо
$('#items').find('.selected').highlight().end().find('.open').updateCount();
// хорошо
$('#items')
.find('.selected')
.highlight()
.end()
.find('.open')
.updateCount();
// плохо
var 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);
// хорошо
var 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);
```
**[[⬆]](#Оглавление)**
## <a name='commas'>Запятые</a>
- Запятые в начале строки: **Нет.**
```javascript
// плохо
var once
, upon
, aTime;
// хорошо
var once,
upon,
aTime;
// плохо
var hero = {
firstName: 'Bob'
, lastName: 'Parr'
, heroName: 'Mr. Incredible'
, superPower: 'strength'
};
// хорошо
var hero = {
firstName: 'Bob',
lastName: 'Parr',
heroName: 'Mr. Incredible',
superPower: 'strength'
};
```
- Дополнительная запятая в конце объектов: **Нет**. Она способна вызвать проблемы с IE6/7 и IE9 в режиме совместимости. В некоторых реализациях ES3 запятая в конце массива увеличивает его длину на 1, что может вызвать проблемы. Этот вопрос был прояснен только в ES5 ([оригинал](http://es5.github.io/#D)):
> Редакция ECMAScript 5 однозначно устанавливает факт, что запятая в конце ArrayInitialiser не должна увеличивать длину массива. Это несемантическое изменение от Редакции ECMAScript 3, но некоторые реализации до этого некорректно разрешали этот вопрос.
```javascript
// плохо
var hero = {
firstName: 'Kevin',
lastName: 'Flynn',
};
var heroes = [
'Batman',
'Superman',
];
// хорошо
var hero = {
firstName: 'Kevin',
lastName: 'Flynn'
};
var heroes = [
'Batman',
'Superman'
];
```
**[[⬆]](#Оглавление)**
## <a name='semicolons'>Точки с запятой</a>
- **Да.**
```javascript
// плохо
(function() {
var name = 'Skywalker'
return name
})()
// хорошо
(function() {
var name = 'Skywalker';
return name;
})();
// хорошо
;(function() {
var name = 'Skywalker';
return name;
})();
```
**[[⬆]](#Оглавление)**
## <a name='type-coercion'>Приведение типов</a>
- Выполняйте приведение типов в начале операции, но не делайте его избыточным.
- Строки:
```javascript
// => this.reviewScore = 9;
// плохо
var totalScore = this.reviewScore + '';
// хорошо
var totalScore = '' + this.reviewScore;
// плохо
var totalScore = '' + this.reviewScore + ' итого';
// хорошо
var totalScore = this.reviewScore + ' итого';
```
- Используйте `parseInt` для чисел и всегда указывайте основание для приведения типов.
```javascript
var inputValue = '4';
// плохо
var val = new Number(inputValue);
// плохо
var val = +inputValue;
// плохо
var val = inputValue >> 0;
// плохо
var val = parseInt(inputValue);
// хорошо
var val = Number(inputValue);
// хорошо
var val = parseInt(inputValue, 10);
```
- Если по какой-либо причине вы делаете что-то дикое, и именно на `parseInt` тратится больше всего ресурсов, используйте побитовый сдвиг [из соображений быстродействия](http://jsperf.com/coercion-vs-casting/3), но обязательно оставьте комментарий с объяснением причин.
```javascript
// хорошо
/**
* этот код медленно работал из-за parseInt
* побитовый сдвиг строки для приведения ее к числу
* работает значительно быстрее.
*/
var val = inputValue >> 0;
```
- **Примечание:** Будьте осторожны с побитовыми операциями. Числа в JavaScript являются [64-битными значениями](http://es5.github.io/#x4.3.19), но побитовые операции всегда возвращают 32-битные значенения. [Источник](http://es5.github.io/#x11.7). Побитовые операции над числами, значение которых выходит за 32 бита (верхний предел: 2,147,483,647).
```
2147483647 >> 0 //=> 2147483647
2147483648 >> 0 //=> -2147483648
2147483649 >> 0 //=> -2147483647
```
- логические типы(Boolean):
```javascript
var age = 0;
// плохо
var hasAge = new Boolean(age);
// хорошо
var hasAge = Boolean(age);
// хорошо
var hasAge = !!age;
```
**[[⬆]](#Оглавление)**
## <a name='naming-conventions'>Соглашение об именовании</a>
- Избегайте однобуквенных имен функций. Имена должны давать представление о том, что делает эта функция.
```javascript
// плохо
function q() {
// ...код...
}
// хорошо
function query() {
// ...код...
}
```
- Используйте camelCase для именования объектов, функций и переменных.
```javascript
// плохо
var OBJEcttsssss = {};
var this_is_my_object = {};
function c() {};
var u = new user({
name: 'Bob Parr'
});
// хорошо
var thisIsMyObject = {};
function thisIsMyFunction() {};
var user = new User({
name: 'Bob Parr'
});
```
- Используйте PascalCase для именования конструкторов классов
```javascript
// плохо
function user(options) {
this.name = options.name;
}
var bad = new user({
name: 'Плохиш'
});
// хорошо
function User(options) {
this.name = options.name;
}
var good = new User({
name: 'Кибальчиш'
});
```
- Используйте подчеркивание `_` в качестве префикса для именования внутренних методов и переменных объекта.
```javascript
// плохо
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
// хорошо
this._firstName = 'Panda';
```
- Создавая ссылку на `this`, используйте название от самого класса в camelCase, вместо `self`/`that`/`_this`/`me` и т.п. Навеяно [отсюда](https://gist.github.com/subzey/8115612).
```javascript
function Rocket() {}
// ...
Rocket.prototype.startMessage = 'Houston, I\'m flying into space!';
// Плохо
Rocket.prototype.start = function () {
var _this = this;
_this.lightsCameraAction(function () {
console.log(_this.startMessage);
});
};
// Хорошо
Rocket.prototype.start = function () {
var rocket = this;
rocket.lightsCameraAction(function () {
console.log(rocket.startMessage);
});
};
```
- Задавайте имена для функций. Это повышает читаемость сообщений об ошибках кода.
```javascript
// плохо
var log = function(msg) {
console.log(msg);
};
// хорошо
var log = function log(msg) {
console.log(msg);
};
```
**[[⬆]](#Оглавление)**
## <a name='accessors'>Геттеры и сеттеры: функции для доступа к значениям объекта</a>
- Функции универсального доступа к свойствам не требуются
- Если вам необходимо создать функцию для доступа к переменной, используйте раздельные функции getVal() и setVal('hello')
```javascript
// плохо
dragon.age();
// хорошо
dragon.getAge();
// плохо
dragon.age(25);
// хорошо
dragon.setAge(25);
```
- Если свойство является логическим(boolean), используйте isVal() или hasVal()
```javascript
// плохо
if (!dragon.age()) {
return false;
}
// хорошо
if (!dragon.hasAge()) {
return false;
}
```
- Вы можете создавать функции get() и set(), но будьте логичны и последовательны – то есть не добавляйте свойства, которые не могут быть изменены через эти функции.
```javascript
function Jedi(options) {
options || (options = {});
var lightsaber = options.lightsaber || 'blue';
this.set('lightsaber', lightsaber);
}
Jedi.prototype.set = function(key, val) {
this[key] = val;
};
Jedi.prototype.get = function(key) {
return this[key];
};
```
**[[⬆]](#Оглавление)**
## <a name='constructors'>Конструкторы</a>
- Присваивайте метод прототипу вместо замены прототипа на другой объект. Замена прототипа на другой объект делает наследование невозможным.
```javascript
function Jedi() {
console.log('new jedi');
}
// плохо
Jedi.prototype = {
fight: function fight() {
console.log('fighting');
},
block: function block() {
console.log('blocking');
}
};
// хорошо
Jedi.prototype.fight = function fight() {
console.log('fighting');
};
Jedi.prototype.block = function block() {
console.log('blocking');
};
```
- Методы могут возвращать `this` для создания цепочек вызовов. Но стоит оставаться последовательным и обеспечить одинаковое поведение для всех методов, кроме геттеров.
```javascript
// плохо
Jedi.prototype.jump = function() {
this.jumping = true;
return true;
};
Jedi.prototype.setHeight = function(height) {
this.height = height;
};
var luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20) // => undefined
// хорошо
Jedi.prototype.jump = function() {
this.jumping = true;
return this;
};
Jedi.prototype.setHeight = function(height) {
this.height = height;
return this;
};
var luke = new Jedi();
luke.jump()
.setHeight(20);
```
- Вы можете заменить стандартный метод toString(), но убедитесь, что он работает и не вызывает побочных эффектов.
```javascript
function Jedi(options) {
options || (options = {});
this.name = options.name || 'no name';
}
Jedi.prototype.getName = function getName() {
return this.name;
};
Jedi.prototype.toString = function toString() {
return 'Jedi - ' + this.getName();
};
```
**[[⬆]](#Оглавление)**
## <a name='events'>События</a>
- Подключая набор данных к событиям (как DOM-событиям, так и js-событиям, например, в Backbone), передавайте объект вместо простой переменной. Это позволяет в процессе всплытия событий добавлять к данному объекту дополнительную информацию.
```js
// плохо
$(this).trigger('listingUpdated', listing.id);
...
$(this).on('listingUpdated', function(e, listingId) {
//делаем что-нибудь с listing, например:
listing.name = listings[listingId]
});
```
prefer:
```js
// хорошо
$(this).trigger('listingUpdated', { listingId : listing.id });
...
$(this).on('listingUpdated', function(e, data) {
// делаем что-нибудь с data.listingId
});
```
**[[⬆]](#Оглавление)**
## <a name='modules'>Модули</a>
- Модуль должен начинаться с `!`. За счет этого даже некорректно сформированный модуль, в конце которого отсутствует точка с запятой, не вызовет ошибок при автоматической сборке скриптов. [Объяснение](https://github.com/airbnb/javascript/issues/44#issuecomment-13063933)
- Файл должен быть именован с camelCase, находиться в папке с тем же именем, и совпадать с именем экспортируемой переменной.
- Добавьте метод noConflict(), устанавливающий экспортируемый модуль в состояние предыдущей версии.
- Всегда объявляйте `'use strict';` в начале модуля.
```javascript
// fancyInput/fancyInput.js
!function(global) {
'use strict';
var previousFancyInput = global.FancyInput;
function FancyInput(options) {
this.options = options || {};
}
FancyInput.noConflict = function noConflict() {
global.FancyInput = previousFancyInput;
return FancyInput;
};
global.FancyInput = FancyInput;
}(this);
```
**[[⬆]](#Оглавление)**
## <a name='jquery'>jQuery</a>
- Для jQuery-переменных используйте префикс `$`.
```javascript
// плохо
var sidebar = $('#sidebar');
// хорошо
var $sidebar = $('#sidebar');
```
- Скрипт должен инициализироваться после готовности `DOM`.
```javascript
// Плохо
$('#login').on('submit', function () {
// Do somthing
});
// Хорошо
$(document).on('ready', function () {
// Do somthing
});
// Лучше
$(function () {
// Do somthing
});
-
Кэшируйте jQuery-запросы. Каждый новый jQuery-запрос делает повторный поиск по DOM-дереву, и приложение начинает работать медленнее.
// плохо function setSidebar() { $("#sidebar").hide(); // ...код... $("#sidebar").css({ backgroundColor: "pink" }); } // хорошо function setSidebar() { var $sidebar = $("#sidebar"); $sidebar.hide(); // ...код... $sidebar.css({ backgroundColor: "pink" }); }
-
Для DOM-запросов используйте классический каскадный CSS-синтаксис
$('.sidebar ul')
или родитель > потомок$('.sidebar > ul')
. jsPerf -
Используйте
find
для поиска внутри DOM-объекта.// плохо $("ul", "#sidebar").hide(); // плохо $("#sidebar") .find("ul") .hide(); // хорошо $("#sidebar ul").hide(); // хорошо $("#sidebar > ul").hide(); // хорошо $sidebar.find("ul").hide();
-
Для поиска одного элемента используйте только идентификатор
#id
.
// плохо
$(".menu button");
// плохо
$(".menu button#menuToggler");
// плохо
$("button#menuToggler");
// хорошо
$("#menuToggler");
- Для поиска нескольких элементов однотипных по функционалу используйте класс с префиксом
.js-*
(для разделения названия класса использовать только дефис-
), а не класс для стилизации элемента, название класса должно быть небольшим, но и понятным.
// плохо
$(".navbar-menu__item");
// плохо
$(".js-navbar-menu__item");
// хорошо
$(".js-nav-link");
**[[⬆]](#Оглавление)**
- Для задания обработчика элементу используйте метод
.on()
.
// Плохо
$input
.click(function() {
/* ... */
})
.focus(function() {
/* ... */
})
.blur(function() {
/* ... */
});
// Хорошо
$input
.on("click", function() {
/* ... */
})
.on("focus", function() {
/* ... */
})
.on("blur", function() {
/* ... */
});
// Лучше
// Несколько событий разделяются пробелами
$field.on("click focus", function() {
/* ... */
});
$input.on({
// Несколько событий разделяются пробелами
"click focus": function() {
/* ... */
},
blur: function() {
/* ... */
}
});
- Для корректной рабоспособности должен быть правильный порядок зависимостей (фреймворков/библиотек/плагинов).
- Своевременно обновляйте зависимости для устранения ошибок и добавления новых фич.
- Не используйте устаервшие и неподдерживамые скрипты.
- Не используйте jQuery версии
2.x
, если поддерживается Internet Explorer 8 и ниже, для этого есть версия1.x
. - Для современных веб-приложений используйте последнюю версию, если нет проблем с совместимостью плагинов и поддерживаются только современные браузеры.
- Опирайтесь на таблицу совместимости с ES5 от Kangax
-
Да.
function() { return true; }
- 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
- В процессе наполнения...
Прочитайте это
Другие руководства по стилю
- Google JavaScript Style Guide
- jQuery Core Style Guidelines
- Principles of Writing Consistent, Idiomatic JavaScript
Другие стили
- Naming this in nested functions - Christian Johansen
- Conditional Callbacks
- Popular JavaScript Coding Conventions on Github
Дальнейшее прочтение
- Understanding JavaScript Closures - Angus Croll
- Basic JavaScript for the impatient programmer - Dr. Axel Rauschmayer
Книги
- 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
Блоги