воскресенье, 15 декабря 2013 г.

javascript best practices

Используйте jQuery

jQuery дает короткий и удобный синтаксис, массу удобных функций, возможность использования цепочек, а также огромное количество плагинов и виджетов, что избавляет от необходимости наладки собственного завода по производству велосипедов.


Не засоряйте глобальное пространство имен

Без оператора var, независимо от того, в каком месте была определена переменная, она станет глобальной. Использование глобальных переменных - очень плохая практика, чреватая трудноуловимыми ошибками. Для того, чтобы переменная получила локальную область видимости, она должна быть объявлена с var:

var $a = "Hello world";

И помните: в javascript переменные имеют функциональную область видимости.




Используйте Венгерскую нотацию

Для лучшей читабельности кода предваряйте переменные с jquery-обертками знаком $:

var $wrapper = $('#wrapper');


Кэшируйте ссылки на DOM-элементы, к которым собираетесь обращаться более одного раза

var $el = $('#element');
$('.link', $el).css('color', '#fff');
$el.children().css('color', '#000');



Объединяйте инициализацию переменных в цепочки

var
  a = 3,
  b = 'hello world';


Используйте делегирование событий

Если на странице будет навешено большое количество обработчиков событий, это может существенно уменьшить производительность. Делегирование событий позволяет бороться с этой проблемой. Еще один плюс делегирования в том, что с его помощью события срабатывают и для элементов, созданных после подвешивания события.

$('document').on('click', '.link', function() {
  $(this).css('border','1px solid red');
$(this).children().css('color','blue');
});


Сохраняйте читабельность кода

Если в цепочке участвует более двух методов, гораздо лучше разбивать их на отдельные строки

$el.html(value);
$second
  .on('click',function(){ alert('hello everybody');})
  .fadeIn('slow')
  .animate({height:'120px'},500);



Используйте всю мощь перегрузки методов jQuery

Многие методы jQuery могут быть использованы с разными аргументами. Рассмотрим это на примере метода .css():

$el
    .css('border','1px solid red')
    .css('color','blue');

В данном случае лучше воспользоваться методом .css() с аргументом в виде объекта:

$el.css({
'border':'1px solid red',
'color' :'blue'
});


Используйте цепочки при вызове jQuery-методов

jQuery после выполнения большинства методов возвращает исходный объект. Это позволяет объединять вызовы jQuery-методов в цепочки:

$el
    .on('click',function(){
  console.log('click el')
    })
    .fadeIn('slow')
    .animate({height:'120px'}, 500);


Извлекайте элементы из DOM-дерева при выполнении ресурсоемких операций

var $el = $("#element").detach();

$.each(items, function(i, val){
    $el.append("<li>"+ val +"</li>");
});
$('#container').append($el);


Оптимизируйте свои селекторы

$('div#element')        => $('#element')
$('div#element a.link') => $('#element .link')
$('#wrapper #element')  => $('#element')
$('#element > *')       => $('#element').children()
$('#element :radio')    => $('#element input:radio');


Всегда указывайте область поиска в селекторах

Во избежание получения элементов лишних элементов, старайтесь указывать область поиска (контекст):

var $links = $('.link', $links_container);

Благодаря использованию $links_container, во-первых, наш запрос будет выполнен быстрее, поскольку поиск будет осуществляться не на всей странице, а только внутри  элемента, указанного в качестве контекста, а во-вторых, вы страхуетесь на случай, если на странице непонятно откуда появятся элементы с таким же классом, они просто не попадут в выборку.


Пишите комментарии к функциям в jsdoc-стиле

В отличие от C++, javascript не является  строго типизированным языком и не требует указания типов.  Поэтому, когда читаешь чужой код, не всегда понятно, какого типа параметры ожидает функция и что она вернет в ответ. Эту проблему прекрасно решает jsdoc-нотация для написания комментариев:

/**
 * Извлечь значение атрибута из объекта по указанному пути
 * @param {String} Путь (атрибуты через точку)
 * @param {Object} Объект, из которого надо извлекать значение
 * @returns {Any} Значение атрибута в объекте по указанному пути
 */
getValByPath: function(path, obj) {
...
}

На первый взгляд она кажется многословной, но в итоге она полностью себя оправдывает. Вторым и главным плюсом jsdoc является возможность автоматической генерации документации.


Не комментируйте очевидные вещи и комментируйте неочевидные вещи

Неоднократно сам наступал на такие грабли, когда открываю свой старый код, смотрю: а там какая-то ерунда, это же можно написать проще и короче, а потом выясняется, что там была некоторая граничная ситуация, о которой я знал когда писал код, но теперь забыл. Такие ситуации надо всегда описывать в коде, иначе другие программисты будут вас проклинать.


Всегда старайтесь использовать 'use strict'

Для того, чтобы внести новые особенности в работу javascript, не поломав при этом старый код, была создана директива 'use strict'. Она указывается в начале файла или в начале функции и благодаря ей интерпретатор начинает вести себя в соответствии с новые стандартом (ES5). Это позволяет избежать потенциальных ошибок и накладывает более жесткие ограничения на код.
 Отменить действие 'use strict' нельзя.  Следует отметить, что 'use strict' не оказывает никакого воздействия на  IE9-. За более подробным описанием работы 'use strict' лучше пойти сюда: http://habrahabr.ru/post/118666/.


Используйте короткие выражения

Зачастую можно встретить такие жуткие конструкции:

var value;
if (flag) {
    value = 0;
} else {
    value = 10;
}

Эту конструкцию можно заменить одной очень простой и элегантной:

var value = flag ? 0 : 10;

Так, ведь намного лучше? И еще один пример распространенной bad-практики:

if ( ! value) value = flag;

Эту же конструкцию можно написать гораздо элегантнее:

value = value || 10;


Помните о приведении типов

Поскольку javascript в операциях сравнения сам тихо и незаметно занимается приведением типов, это может сыграть злую шутку. Например, во всех приведенных ниже случаях результатом сравнения будет true:

'1' == 1
'0' == false
[1] == 1
[]  == 0
[]  == ![]

Лично меня сильно пугают подобные преобразования, поэтому в ряде случаев всем рекомендую вместо == использовать === (тождественное равенство). Оно позволяет избежать приведения типов в операциях сравнения.


Пишите тесты

Код, который на первый взгляд работает правильно, может давать сбои в ряде граничных случаев. Когда вы пишете тесты, вы непроизвольно продумываете такие случаи и учитываете их в коде. К тому же, при внесении изменений в код, для которого написаны тесты, можно быстро убедиться, что никакой функционал не был потерян. Однако, и в крайности вдаваться не надо. Покрывать весь код на все 100% тестами - очень дорогое и глупое занятие.


Sources:
http://flippinawesome.org/2013/11/25/writing-better-jquery-code/
http://ruseller.com/lessons.php?rub=32&id=1923