Лучшие практики jQuery

Простые, но очень полезные, рекомендации по написанию кода с использованием jQuery описал Abhinay Rathore в статье «jQuery Coding Standards & Best Practices». Я переводил ее для использования в качестве инструкции для верстальщиков в компании, в которой работаю. Материал активно используется и может быть полезен в том числе как чек-лист.

Подключение библиотеки

  1. Всегда используйте CDN для подключения jQuery к странице:

    <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
    <script>window.jQuery || document.write('<script src="js/jquery-2.1.4.min.js" type="text/javascript"><\/script>')</script>
    
  2. В строке запроса обязательно указывайте точную версию библиотеки. Например, 2.1.4 вместо 2.1 или 2. Никогда не используйте jquery-latest.js из jQuery CDN.

  3. Никогда не подключайте к странице несколько версий библиотек.

  4. Предусматривайте в коде возможность загрузки локальной копии библиотеки, если CDN недоступна:

    <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
    <script>window.jQuery || document.write('<script src="js/jquery-2.1.4.min.js" type="text/javascript"><\/script>')</script>
    
  5. Используйте независимые от протокола схемы URL (опускайте http: и https: в аттрибуте src).

  6. Старайтесь подключать JS-код всегда в конце страницы.

  7. Если к странице подключены другие библиотеки (например, Zepto, MooTools), которые используют переменную $, старайтесь не обращаться к $ для вызова jQuery-функций. Освободите имя $ с помощью jQuery.noConflict() и обращайтесь просто к объекту jQuery.

    $.noConflict();
    jQuery(document).ready(function($) {
        // используем jQuery с $
    });
    // используем другую библиотеку с $
    
  8. Для определения расширенных возможностей браузера используйте Modernizr.

Переменные jQuery

  1. Все переменные, которые хранят или кэшируют объекты jQuery, должны иметь префискс $.

  2. Всегда кэшируйте объекты, возвращаемые jQuery-селекторами, для повторного использования:

    var $myDiv = $("#myDiv");
    $myDiv.click(function(){...});
    
  3. Используйте строго camelCase для именования переменных.

Селекторы

  1. Используйте ID-селекторы всякий раз, когда возможно. Они работают значительно быстрее, поскольку управление передается нативному JS-методу document.getElementById().

  2. Используя селектор на основе класса, опускайте тип элемента:

    var $products = $("div.products"); // медленно
    var $products = $(".products"); // быстро!
    
  3. Используйте метод .find() для обращения к дочерним вложенным элементам. Подход на основе метода .find() работает быстрее, поскольку для первой выборки не используется движок Sizzle:

    // Плохо, используется движок Sizzle
    var $productIds = $("#products div.id");
    // Хорошо, #products уже выбран с помощью `document.getElementById()` и только div.id будет передан движку Sizzle:
    var $productIds = $("#products").find("div.id");
    
  4. Конкретизируйте селектор с правой стороны и, наборот, обобщайте с левой:

    // Плохо
    $("div.data .gonzalez");
    // Хорошо
    $(".data td.gonzalez");
    
  5. Избегайте чрезмерной конкретизации:

    // Плохо
    $(".data table.attendees td.gonzalez");
    // Лучше (оптимизируйте по мере возможности)
    $(".data td.gonzalez");
    
  6. Передавайте селектору контекст.

    // Медленно, потому что выполняется обход всей модели DOM для класса .class
    $('.class');
    // Быстро, потому что область поиска ограничена #class-container
    $('.class', '#class-container');
    
  7. Избегайте использования универсальных селекторов:

    // Плохо
    $('div.container > *');
    // Хорошо
    $('div.container').children();
    
  8. Избегайте использования универсальных селекторов, наличие которых подразумевается:

    // Плохо
    $('div.someclass :radio'); 
    // Хорошо
    $('div.someclass input:radio');
    
  9. Не смешивайте несколько ID с другими селекторами. Помните, что выбор обеспечивается document.getElementById():

    $('#outer #inner'); // Плохо
    $('div#inner'); // Плохо
    $('.outer-container #inner'); // Плохо
    $('#inner'); // Хорошо, происходит вызов только document.getElementById()
    

Работа с деревом DOM

  1. Всегда выполняйте .detach() для элементов, которые собираетесь обрабатывать. По окончании обработки возвращайте их в дерево:

    var $myList = $("#list-container > ul").detach();
    //... действия по обработке $myList
    $myList.appendTo("#list-container");
    
  2. Используйте конкатенацию строк или array.join() вместо .append():

    // Плохо
    var $myList = $("#list");
    for(var i = 0; i < 10000; i++){
        $myList.append("<li>"+i+"</li>");
    }  
    // Хорошо
    var $myList = $("#list");
    var list = "";
    for(var i = 0; i < 10000; i++){
        list += "<li>"+i+"</li>";
    }  
    $myList.html(list);
    // Еще лучше
    var array = []; 
    for(var i = 0; i < 10000; i++){
        array[i] = "<li>"+i+"</li>"; 
    }
    $myList.html(array.join(''));
    
  3. Не взаимодействуйте с отсутствующими элементами:

    // Плохо. Этот код запускает три функции, прежде чем понимает, что выборка пуста.
    $("#nosuchthing").slideUp();
    // Хорошо
    var $mySelection = $("#nosuchthing");
    if ($mySelection.length) {
        $mySelection.slideUp();
    }
    

События

  1. Используйте на странице только один обработчик Document Ready. Это упрощает отладку.

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

    // Плохо
    $("#myLink").on("click", function(){...});
    // Хорошо
    function myLinkClickHandler(){...}
    $("#myLink").on("click", myLinkClickHandler);
    
  3. Обработчик события Document Ready также не должен быть анонимной функцией.

    // Плохо. Вы не сможете повторно использовать этот код или написать тест к нему.
    $(function(){ ... }); 
    // Хорошо
    $(initPage); // или $(document).ready(initPage);
    function initPage(){
        // Cобытие загрузки страницы, где можно инициализировать значения и вызывать другие инициализаторы.
    }
    
  4. Обработчики события Document Ready должны подключаться из внешних файлов:

    <script src="my-document-ready.js"></script>
    <script>
        // Любые глобальные переменные, которые могут понадобиться.
        $(document).ready(initPage); // или $(initPage);
    </script>
    
  5. Не используйте инлайновый JavaScript. Сложно выполнять его отладку. Всегда назначайте события с помощью jQuery. Их легко динамически подключать и отключать.

    <a id="myLink" href="#" onclick="myEventHandler();">my link</a> <!-- Плохо! -->
    
    $("#myLink").on("click", myEventHandler); // Хорошо
    
  6. Если возможно, используйте собственные пространства имен для событий. С их помощью легко отключать одни события, не затрагивая другие.

    // Отлично
    $("#myLink").on("click.mySpecialClick", myEventHandler);
    // Затем легко отключить событие
    $("#myLink").unbind("click.mySpecialClick");
    
  7. Используйте делегирование, чтобы применить одно и то же событие для нескольких элементов. Понадобится всего один раз назначить событие родительскому элементу, и оно будет срабатывать для всех потомков, соответствующих селектору, вне зависимости от того, существуют ли элементы на данный момент или будут добавлены в дерево позже.

    // Плохо
    $("#list a").on("click", myClickHandler); 
    // Хорошо
    $("#list").on("click", "a", myClickHandler); 
    

AJAX

  1. Избегайте использования методов .getJson() и .get(), просто вызывайте $.ajax().

  2. Используйте независимые от протокола схемы URL (опускайте http: и https: в строке запроса).

  3. Параметры запроса указывайте только с помощью свойства data:

    // Плохо
    $.ajax({
        url: "something.php?param1=test1&param2=test2",
        ....
    });
    // Хорошо
    $.ajax({
        url: "something.php",
        data: { param1: test1, param2: test2 }
    });
    
  4. Старайтесь указывать dataType.

  5. Используйте Delegated event handlers для назначения событий контенту, загруженному через AJAX:

    $("#parent-container").on("click", "a", delegatedClickHandlerForAjax);
    
  6. Используйте объект Promise для отложенных и асинхронных вычислений

    $.ajax({ ... }).then(successHandler, failureHandler);
    // или
    var jqxhr = $.ajax({ ... });
    jqxhr.done(successHandler);
    jqxhr.fail(failureHandler);
    
  7. Простой AJAX-шаблон:

    var jqxhr = $.ajax({
        url: url,
        type: "GET", // по умолчанию GET, но вы можете использовать другие типы
        cache: true, // по-умолчанию true, но используйте false, если dataType 'script' и 'jsonp'.
        data: {}, // параметры запроса
        dataType: "json", // конкретизируйте dataType
        jsonp: "callback", // cервер кодирует данные в JSON и оборачивает их в вызов функции, название которой получает из параметра callback
        statusCode: { // если хотите обрабатывать специфичесие коды ошибок, используйте отображения:
            404: handler404,
            500: handler500
        }
    });
    jqxhr.done(successHandler);
    jqxhr.fail(failureHandler);
    

Эффекты и анимация

  1. Придерживайтесь сдержанного и последовательного подхода к использованию анимации.

  2. Отдавайте приоритет простым (show/hide, toggle и slideUp/slideDown) эффектам.

  3. Старайтесь использовать предопределенные значения скорости анимации ("slow", "fast" и т. д.).

Плагины

  1. Всегда выбирайте хорошо документированные плагины с хорошим сообществом поддержки.

  2. Проверяйте совместимость плагина с используймой версией jQuery.

  3. Любой компонент, который предполагается использовать повторно, всегда оформляйте в виде плагина (см. тему jQuery Plugin Boilerplate в Интернете).

Цепочки кода

  1. Используйте цепочки кода как альтернативу новым переменным или множественным вызовам селекторов:

    $("#myDiv").addClass("error").show();
    
  2. Всякий раз, когда цепочка содержит более трех звеньев или усложняется за счет назначения событий, используйте разрывы строк и отступы, чтобы сделать код удобным для чтения.

    $("#myLink")
        .addClass("bold")
        .on("click", myClickHandler)
        .on("mouseover", myMouseOverHandler)
        .show();
    
  3. В длинных цепочках допустимо кэшировать промежуточные объекты в переменные.

Прочие рекомендации

  1. Используйте литералы объектов для передачи параметров:

    // Плохо, три вызова attr()
    $myLink.attr("href", "#").attr("title", "my link").attr("rel", "external");
    // Хорошо, attr() вызывается всего один раз
    $myLink.attr({
        href: "#",
        title: "my link",
        rel: "external"
    });
    
  2. Не смешивайте CSS с jQuery.

    // Плохо
    $("#mydiv").css({'color':red, 'font-weight':'bold'});
    // Хорошо
    .error { color: red; font-weight: bold; }
    $("#mydiv").addClass("error");
    
  3. Не используйте устаревшие методы (Deprecated Methods).

  4. Сочетайте код jQuery с нативным кодом JavaScript, если это необходимо:

    $("#myId"); // работает немного медленнее, чем...
    document.getElementById("myId");
    

Статья является переводом материала Abhinay Rathore «jQuery Coding Standards & Best Practices».