В очередной раз открыв код коллег и ужаснувшись, я решил написать эту статью. Надеюсь для кого-нибудь это будет полезным, заодно и мне будет проще новичкам объяснять что у них в коде не так, просто кинув ссылку на эту статью.
Безусловно количество таких вещей очень и очень велико, поэтому в статье ограничусь лишь некоторыми.
1. Константы в коде
Эта проблема касается не только javascript, а программирования в целом. Рассмотрим пример:
$elem.on('keydown', function(e) {
if (e.keyCode == 27) {
//...
}
});
Что за магическое число 27? Люди, которые часто сталкиваются с кодами сразу скажут — это же клавиша ESC. Но большинство разработчиков, особенно начинающих, либо не помнят эти коды, либо не знают вообще, и сталкиваясь с кодами, вынуждены в очередной раз лезть в поисковую систему и тратить время.
Можно конечно добавить комментарий в коде, что это обработка нажатия клавиши ESC, но гораздо эффективнее было бы ввести константу, например, KEY_ESC = 27
2. Получение идентификаторов
Часто возникает необходимость получить идентификатор элемента (комментария, поста, пользователя и т.п.), чтобы выполнить какие-нибудь действия. (например, оценить комментарий при помощи ajax). И часто можно встретить подобный подход:
var id = $(this).attr('id').substring(8);
Как и в предыдущем примере разработчику приходится гадать — что же это за число 8. Лезть в html код и т.п.
Бывают примеры и хуже (строчка скопирована с реального проекта):
var last_id = $('#answer_pid' + id + ' li:first div').attr('id').substr(7);
Малейшее изменение верстки приведет к тому, что js код придется править.
Иногда бывает такое:
<div class="comment" id="comment_123"></div>
var id = $(this).attr('id').substring("comment_".length);
Уже лучше (по крайней мере нет вшитых чисел), но все равно данный подход слишком сильно привязывает js код к html.
На мой взгляд гораздо лучше использовать data-* параметры, например
<div class="comment" data-id="123"></div>
тогда получить идентификатор будет очень просто:
var id = $(this).attr('data-id');
или
var id = $(this).data('id');
(Про отличия в работе attr и data есть множество статей)
3. $.post
Как известно — в jquery есть метод для работы с ajax — $.ajax. К нему есть несколько shorthand функций, таких как $.get, $.load, $.post и т.п. Данные функции были добавлены специально, чтобы облегчить часто выполняемые действия (подгрузить скрипт, json, выполнить post запрос), но в реализации все эти методы ссылаются на $.ajax.
Лично я никогда не использую shorthand функции, и вот почему:
В коде начинающих или малоопытных разработчиков можно встретить несколько разных стадий:
1. Начальный
$.post(url, data, function(data) {
data = $.parseJSON(data);
//...
});
2. Добавляется try catch блок
$.post(url, data, function(data) {
try {
data = $.parseJSON(data);
} catch (e) {
return;
}
//...
});
3. Узнаем из документации, что в $.post последним параметром можно передать dataType (который пропадает в безде кода, если success функция не влезает в экран).
$.post(url, data, function(data) {
//...
}, 'json');
Очень редко веб разработчики добавляют обработчики ошибочных ситуаций. В основном это происходит из-за лени, либо нежелании потратить лишние 5 минут времени, либо разработчики просто уверены, что ошибок никогда не будет.
Если же разработчик решил к $.post добавить обработчик ошибок, то получается нечто вроде:
$.post(url, data, function(data) {
//...
}, 'json').error(function() {
///
});
На мой взгляд — это ужасно нечитабельно. Да и писать каждый раз обработчик ошибок — дело нудное, поэтому можно настроить обработчик ошибок по умолчанию для всех ajax запросов, например:
$.ajaxSetup({
error: function() {
//Показать окошко о том, что произошла ошибка
}
});
Вернемся к $.post. Как показано выше — использование $.post делает код ужасным (особенно с dataType в непонятном месте). Перепишем последний пример на $.ajax. На мой взгляд данный подход читабельнее и проще в поддержке.
$.ajax({
type: "POST"
url: url,
data: data,
dataType: "json",
success: function(data) {
//
},
error: function() {
//
}
})l
4. Обработчики событий к нескольким элементам
Часто бывает необходимость добавить обработчики событий к элементам страницы (например, кнопка «удалить сообщение»). И зачастую можно встретить подобный подход:
$('.comment a.delete').click(function(){
//
});
Минусы этого подхода — в памяти создаются N абсолютно одинаковых обработчиков, поэтому если на странице 1000 комментариев — потребление памяти будет существенным.
Еще одна проблема — добавить обработчик к новому элементу. И тут я видел множество решений, включая переопределение всех обработчиков заново (нередко копипастом содержимого обработчиков):
$('.comment a.delete').unbind('click').click(function() {
//
});
Решение: в jQuery 1.7 есть метод on, который привязывает обработчики события, фильтруя элементы по селектору.
пример:
$('body').on('click', 'a.external', function(e) {
//функция будет вызвана при клике на любую ссылку с классом external
});
При этом важно, что данный обработчик работает и для динамически создаваемых объектов.
Стоит также заметить, что данный подход нужно применять с умом. Например следующий код может привести к снижению производительности и подтормаживаниям браузера:
$('body').on('mousemove', selector, function() {
//
});
5. Namespaced events
Несмотря на то, что namespaced events были добавлены в jQuery 1.2 — ими мало кто пользуется (Мне кажется большинство людей просто не знают о них).
Рассмотрим пример:
$('a').on('click', function() {
//обработчик 1
});
$('a').on('click', function() {
//обработчик 2
});
Теперь предположим, что нам нужно удалить второй обработчик от ссылок. Но вот ведь незадача — $('a').off('click') удалит оба обработчика. На помощь приходит namespaced events. Перепишем код выше:
$('a').on('click.namespace1', function() {
//обработчик 1
});
$('a').on('click.namespace2', function() {
//обработчик 2
});
Теперь становится возможным удалить второй обработчик при помощи вызова $('a').off('click.namespace2');
Подробнее о namespaced events можно прочитать здесь: docs.jquery.com/Namespaced_Events
Вместо заключения
Это лишь небольшая часть тех проблем, с которыми я регулярно сталкиваюсь в чужом коде. Надеюсь что данный пост поможет улучшить качество кода.
Автор: Sirian