Правила эффективного использования jQuery

    Здесь приведен ряд очень простых правил, следуя которым, ваше сотрудничество с jQuery не будет омрачено скрежетом напрягшегося браузера. Конечно, не так часто случается, что скорость работы javascript’а оказывается критичной, однако такое все же может произойти, и произойти в самый неподходящий момент. Поэтому, лучше держать эти правила в голове и не пренебрегать ими.


    1. Эффективный поиск элементов


    Быстрее всего происходит поиск элементов по идентификатору: $('#someId'), вторым по быстродействию, является поиск по имени тега: $('tagName'). Высокая скорость их выполнения связана с тем, что для их реализации используются внутренние функции javascript: getElementById() и getElementsByTagName(). В связи с этим, появляются несколько правил.

    (Для большей наглядности, укажу текст страницы, к которому будут применен JS-код из примеров)
    <div id="content">
      <form method="post" action="/">
        <h2>Выбери цвет</h2>
        <ul id="color_light">
          <li><input type="radio" class="on" name="light" value="red" /> Красный</li>
          <li><input type="radio" class="off" name="light" value="yellow" /> Желтый</li>
          <li><input type="radio" class="off" name="light" value="green" /> Зеленый</li>
        </ul>
        <input class="button" id="color_button" type="submit" value="Go" />
      </form>
    </div>

    * This source code was highlighted with Source Code Highlighter.


    1. Если вы ищете один элемент, используйте поиск по идентификатору:
    $('#color_button') – будет выполнен максимально быстро
    $('#content .button') – будет медленнее
    $('.button:first') – еще медленнее

    2. Если вы ищете группу элементов, указывайте ближайшего общего родственника, обладающего идентификатором:
    $('#content input') будет эффективнее, чем просто $('input').

    3. Если вы ищете элементы по классу, указывайте имя тега:
    $('input.button') выполнит поиск быстрее, чем $('.button'). В первом случае, jQuery вначале найдет все элементы input, и уже среди них будет искать элементы с классом button. А во втором случае, для этого будет произведен перебор всех элементов страницы.

    Из всего сказанного, можно вывести два основных правила:
    1) Для поиска одного элемента, используйте поиск по id: $('#someId')
    2) При поиске группы элементов, старайтесь придерживаться следующей формулы: $('#someId tagName.someClass')

    И еще, не пытайтесь улучшить поиск по id с помощью следующих комбинаций:
    $('tagName#someId')
    $('#wrapId #someId')

    Это только замедлит выполнение поиска.

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


    Не следует производить поиск одних и тех же элементов снова и снова, это достаточно дорогостоящая процедура, даже если вы используете самый быстрый селектор:
    $('#myElement').bind('click', function(){...});
    . . .
    $('#myElement').css('border', '3px dashed yellow');
    . . .
    $('#myElement').fadeIn('slow');

    В этом случае, jQuery каждый раз будет осуществлять поиск элемента с идентификатором myElement. Гораздо разумнее будет найти элемент один раз, сохранить его, а затем применять к нему необходимые операции:
    var myElement = $('#myElement');
    . . .
    myElement.bind('click', function(){...});
    . . .
    myElement.css('border', '3px dashed yellow');
    . . .
    myElement.fadeIn('slow');


    Если на протяжении работы вашего скрипта часто используются одни и те же элементы, то будет разумно найти эти элементы только один раз и сохранить результат в глобальной переменной:
    window.elements;
    function init()
    {
      elements = $('#someId tagName.someClass');
    }

    Правда, иногда, необходимо совершать манипуляции с разными группами элементов, которые, однако, являются связанными. Например, это могут быть элементы формы, с которыми необходимо совершать много манипуляций. В таком случае, нам постоянно придется искать нужные элементы:
    $('#myForm input:checkbox') // все флажки
    $('#myForm input:text') // все текстовые поля
    $('#myForm input:text[value != ""]') // все непустые текстовые поля
    . . .

    Вместо этого, можно найти все элементы формы один раз, и при необходимости доставать оттуда необходимые:
    var inputs = $('#myForm input');
    inputs.filter(':checkbox') // найдем все флажки
    inputs.filter(':text') //найдем все текстовые поля
    inputs.filter(':text[value != ""]') // найдем все непустые текстовые поля
    . . .

    Или, вам может потребоваться совершать много манипуляций с элементами списка, в том числе удалять и добавлять их. В таком случае, «кэшировать» элементы списка не будет хорошей идеей, поскольку их состав будет постоянно меняться, а «кэш» оказываться неактуальным. Однако, можно сохранить объект самого списка в глобальной переменной, что тоже значительно сократит вычислительные затраты:
    myList = $('#myList');
    . . .
    myList.find('li:first').remove(); // найдем и удалим первый элемент списка
    myList.find('li.showed').hide(); // скроем все элементы списка с классом showed


    3. Избегайте лишних манипуляций c DOM


    Основной идеей здесь является то, что если вы хотите внести ряд изменений на странице (добавить/изменить элемены), проделывайте эти манипуляции локально и только после этого вносите изменения в DOM. Например, если вы хотите добавить в список сто новых элементов, то ошибочным будет делать это поэлементно:
    var top_100_list = [...]; // содержимое новых элементов
    $mylist = $('#mylist'); // необходимый список

    for (var i=0; i< top_100_list.length; i++)
      $mylist.append('<li>' + top_100_list[i] + '</li>');

    гораздо эффективнее будет вставить сразу все элементы:
    var top_100_list = [...]; // содержимое новых элементов
    var li_items = ""; // вставляемый html-текст
    $mylist = $('#mylist'); // необходимый список

    for (var i=0; i< top_100_list.length; i++)
      li_items += '<li>' + top_100_list[i] + '</li>';
    $mylist.append(li_items);

    Еще больший выигрыш можно получить, если группа вставляемых элементов окажется «обернутой» одним элементом. Поэтому, если бы у нас была задача заменить содержимое списка сотней новых элементов, то самым оптимальным, был бы такой вариант:
    var top_100_list = [...]; // содержимое новых элементов
    var new_ul = "<ul id='mylist'>"; // вставляемый html-текст
    $mylist = $('#mylist'); // необходимый список

    for (var i=0; i< top_100_list.length; i++)
      new_ul += '<li>' + top_100_list[i] + '</li>';
    new_ul += "</ul>";
    $mylist.replaceWith(new_ul);


    Изменять элементы локально, поможет метод clone(), который создает копии элементов, вместе со всем их содержимым. Произведя все необходимые изменения с копиями, можно вставить их обратно в DOM, вместо старых версий (это можно сделать с помощью метода replaceWith()).

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


    Иногда, приходится устанавливать одинаковые обработчики событий на большую группу элементов. Например, может потребоваться установить обработчики нажатия мышью, элементам списка. В таких случаях, вместо того, чтобы устанавливать обработчики на каждый элемент списка, можно установить один обработчик на сам список. Как известно, стандартные события javascript, вызванные на каком-либо элементе, затем вызываются на всех его предках (родительском элементе, затем прародительском и.т.д). Поэтому, после того, как событие произойдет на конкретном элементе списка, оно будет вызвано на объекте самого списка. Понять, у кого именно произошло событие, поможет передаваемый в обработчик объект event, а точнее, его свойство event.target. Оно всегда содержит DOM-объект первоначального источника события:
    $('#myList').click(function(event){
      $(event.target).addClass('clicked'); // добавим нажатому элементу класс clicked
    });
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 151
    • +3
      Признайтесь, это статья ваша? Где-то я видел уже ее на забугорном сайте.
      Если это перевод — отметьте это.
      • +4
        Ну, она написана не с нуля. Я прочитал несколько статей на эту тему, перед тем как ее писать. В основном, я использовал материалы вот этой статьи. Но я не знаю, считать ли это переводом, я значительно переработал материал.
        • +4
          А mabp.kiev.ua/2009/08/10/presentation-from-coffee-n-code/ пропустили-то :) Перфоманс выборки очень зависит от браузера, конкретно от поддержки querySelectorAll (querySelector).

          Сейчас гораздо большей эффективности добавит разделение селектора на те, которые написаны по CSS3 правилам и на остальные. Первые выполнятся очень быстро через нативный querySelectorAll, остальные фильтранет Sizzle:

          $("#id .class tag:visible")
          лучше выбрать так:
          $("#id .class tag").filter(":visible")

          Ну, и не стоит забывать о совсем олдскульных трюках: в примере, где формируется DOM-строка, в IE6 все равно все будет грустно. Все маленькие строки лучше складывать в массив, а потом join-ить его. Я понимаю, что здесь речь о перфомансе jQuery, но в этом примере с водой выплеснули и ребенка:

          вместо:
          var li_items = "";
          for (var i=0; i< top_100_list.length; i++)
          li_items += '' + top_100_list[i] + '';
          $mylist.append(li_items);

          лучше:
          var li_items = [];
          for (var i=0; i< top_100_list.length; i++)
          li_items.push('' + top_100_list[i] + '');
          $mylist.append(li_items.join(''));
          • +1
            Спасибо за ссылочку на меня любимого ;) От себя добавлю еще что это все было про jQuery 1.3.2, а текущая 1.4.2 и в ней есть пару нюансов

            >>$('#color_button') – будет выполнен максимально быстро
            >>$('#content .button') – будет медленнее
            Я не думаю что вы правильно сравниваете. В первом случаи вы ищете однозначно один элемент, во втором — группу, то что вы находите один элемент это частный случай.
            Более того в 1.4 был оптимизирован поиск по селекторам начинающимся на # (пруфлинк), так что совет вообще не в кассу

            >>3. Избегайте лишних манипуляций c DOM
            я тут вот еще что накрапал для любителей делать как красиво и неправильно.

            Это же касается замечания про ie6, лучше тогда уже делать вот так
            $.fn.append.apply($mylist, li_items)

      • +11
        var myElement = $('#myElement');
        myElement.bind('click', function(){...});
        myElement.css('border', '3px dashed yellow');
        myElement.css('background-color', 'orange');
        myElement.fadeIn('slow');
        Можно проще:
        $('#myElement').bind('click', function(){...}).css('border', '3px dashed yellow').css('background-color', 'orange').fadeIn('slow');
        • 0
          Да ну:)… Мне кажется автор написал это для наглядности. Ваш вариант быстрее работать не будет.
          А если вы хотели сократить, то рекомендую посмотреть внимательнее метод css.
          • 0
            Зато весит меньше и не нуждается в доп. переменной.
            • +5
              Тогда уж так, сохраняя плюсы обоих подходов:
              var myElement = $('#myElement')
                  .bind('click', function(){...})
                  .css('border', '3px dashed yellow')
                  .css('background-color', 'orange')
                  .fadeIn('slow');
              
              • 0
                var myElement = $('#myElement')
                    .bind('click', function(){...})
                    .css({
                        'border': '3px dashed yellow',
                        'background-color': 'orange'
                    })
                    .fadeIn('slow');


                Кто продолжит эстафету?
                • 0
                  Чорт, не увидел ниже такой же кусок кода. Прошу прощения за дублирование.
            • –2
              По идее и работать должен быстрее, не надо каждый раз разыменовывать переменную, мизер, но всё же
            • +4
              с точки зрения философии jQuery, это еще и самый правильный метод. А еще я читал, что jQuery давно научился кешировать объекты, т.е.:
              $('.some_class')... // поиск будет медленный
              ...
              ...
              $('.some_class')... // jQuery возьмет из кеша, поиска не будет
              
              • 0
                Можно пруф?
                Пока слышал, что это выдумка, ибо сделать не так то просто: надо постоянно отслеживать не добавили ли таких элементов в DOM, или не удалили старые.
                Проще логику кеширования вынести из фреймворка, и просто запоминать нужные тебе элементы.
                • +1
                  Пруф не нашел :(

                  По поводу:

                  Кеширование в domManip
                  jQuery кэширует узлы, созданные с использованием таких методов, как jQuery("") и .after(""). Благодаря этому увеличивается производительность на страницах, на которых выполняются DOM-манипуляции со строками, использующих эти методы.
                  • 0
                    сорри, отправилось рано:

                    По поводу:
                    > не добавили ли таких элементов в DOM, или не удалили старые.

                    w3pro.ru/article/ob-izmeneniyakh-v-jquery-14-po-sravneniyu-s-predydushchei-versiei
                    Кеширование в domManip
                    jQuery кэширует узлы, созданные с использованием таких методов, как jQuery("") и .after(""). Благодаря этому увеличивается производительность на страницах, на которых выполняются DOM-манипуляции со строками, использующих эти методы.
                    • 0
                      Получается при поиске никакого кеширования результатов нет.
                      По этому коменту в общем всё видно.
                  • 0
                    Кэширования нет, в исходниках jQuery это видно
                  • +1
                    Как отметили выше, давайте дополируем:

                    $('#myElement')
                        .bind('click', function(){...})
                        .css({
                           'border'           : '3px dashed yellow',
                           'background-color' : 'orange'
                        }).fadeIn('slow');
                    
                    • 0
                      Логично предположить что кликнутый элемент становится активным. Соответсвенно можно упростить addClass/removeClass. В таком случае будет правильно разделены стилизация и функциональность.

                      $('#myElement')
                          .bind('click', function(){...})
                          .addClass('activeState')
                          .fadeIn('slow');
                      
                      • +2
                        Да, и при анимациях рекомендую использовать .stop() а потом .fadeIn() или animate()
                        • 0
                          тогда уже не просто .stop(), а .stop(true, true) потому что если при полной видимости (только не fade, a slide) эти элементы накладываются то может получиться забавный эффект когда они оба анимируются по очереди ;)
                        • +1
                          СSS применялось просто так, а не по клику, оно же не в обработчике — это поправка к Вашему описанию

                          А так, я тоже за вынос правил оформления через класс в CSS
                        • 0
                          $('#myElement')
                          .click( function(){...} )
                          .addClass('activeState')
                          .fadeIn('slow');
                      • 0
                        Я немного подправил этот код в статье. Я хотел показать, что если на протяжении одного блока кода, вам необходимо работать с одними и теми же элементами, то их кеширование приведет к экономии ресурсов. То есть, совсем не обязательно, что обращение к этим элементам будет происходить друг за другом. Исправил на такой вариант:
                        var myElement = $('#myElement');
                        . . .
                        myElement.bind('click', function(){...});
                        . . .
                        myElement.css('border', '3px dashed yellow');
                        . . .
                        myElement.fadeIn('slow');
                      • –1
                        Хм, был удивлен 2 пунктом, меня неоднократно убеждали в том что jQuery хорош именно тем, что кеширует результаты поиска.
                        • +3
                          Сейчас сделал небольшой скрипт для тестирования скорости.
                          for(var i = 0; i<5000; i++)
                            $("li.stop").attr("class");

                          выполняется за три секунды, а
                          var el = $("li.stop");
                          for(var i = 0; i<5000; i++)
                            el.attr("class");

                          за треть секунды. То есть разница примерно в 10 раз. Однако, при поиске по идентификатору, разница только в два раза.
                        • +2
                          Как всегда одно и тоже из серии: «Бла-бла-бла для чайников». И ошибки все старые. Вот вы в код-то самой jquery заглядвали? Откуда вы взяли, что поиск будет быстрее по идентификатору? Там по коду вначале идет проверка на то, есть ли вообще селектор (не равен ли он пустой строке), далее не DOM-элемент ли, далее не равен ли селектор строке «body» с отсутствующим контекстом, а уж после того только начинается анализ строки селектора, если предыдущие проверки не сработали. Из этого можно сделать вывод, что тот же тег body найдется быстрее по названию, нежели по id.
                          • 0
                            Поправка, проверка на наличие селектора: не равне ли он пустой строке / null / undefined.
                            • 0
                              Нет, код jquery мне разбирать еще не доводилось. Сейчас сделал скрипт для тестирования, элемент body находится действительно быстрее, процентов на 20, в нескольких других случаях, поиск по идентификатору чуть быстрее поиска по тегам (разница около 10%).
                              • 0
                                Я надеюсь при тестировании Вы отключили нативную выборку по селектору (document.querySelectorAll)?
                                • +2
                                  То есть Вы написали статью про performance tips в jQuery, даже не удосужившись почитать код самого фреймворка? Хм-хм.
                                  • 0
                                    зато сколько плюсов отхватил… вот в чём моя ошибка была оказывается х)
                                • НЛО прилетело и опубликовало эту надпись здесь
                                • НЛО прилетело и опубликовало эту надпись здесь
                                  • +1
                                    Неправда. Эта функция есть отнюдь не во всех браузерах.
                                    • –3
                                      Насколько я знаю этой функции вообще нет в браузерах, поскольку она только планируется в HTML5:
                                      www.w3.org/TR/html5/dom.html#dom-document-getelementsbyclassname
                                      • НЛО прилетело и опубликовало эту надпись здесь
                                        • 0
                                          Вообще-то наверное чуток соврал:
                                          01  if(document.getElementsByClassName) { // если есть родная фукнция, используем ее *
                                          02    getElementsByClass = function(classList, node) { 
                                          03      return (node || document).getElementsByClassName(classList) // вызываем метод getElementsByClassName нужного узла.
                                          04      // если указан node, то будет произведен поиск в нем, иначе во всем документе
                                          05    }
                                          06  
                                          07  } else { // если родной функции нет, то будем обходить DOM
                                          08    getElementsByClass = function(classList, node) {     
                                          09      var node = node || document, // узел, в котором ищем
                                          10        list = node.getElementsByTagName('*'), // выбираем все дочерние узлы
                                          11        length = list.length, // количество дочерних узлов
                                          12        classArray = classList.split(/\s+/), // разбиваем список классов
                                          13        classes = classArray.length, // длина списка классов
                                          14        result = [], i,j
                                          15      for(i = 0; i < length; i++) { // перебираем все дочерние узлы
                                          16        for(j = 0; j < classes; j++) { //перебираем все классы
                                          17          if(list[i].className.search('\\b' + classArray[j] + '\\b') != -1) { // если текущий узел имеет текущий класс
                                          18            result.push(list[i]) // запоминаем его
                                          19            break // прекращаем перебор классов
                                          20          }
                                          21        }
                                          22      }
                                          23    
                                          24      return result // возвращаем набор элементов
                                          25    }
                                          26  }


                                          * This source code was highlighted with Source Code Highlighter.


                                          * // если есть родная фукнция, используем ее
                                          Значит предпологается что где-то родная функция есть… =)
                                          • 0
                                            Конечно дико извиняюсь — но вот в спецификациях HTML4 так сразу не нашел. Если можно ссылочку на w3c. Если ссылочки не будет — функцию нельзя назвать нэтивной.
                                            • 0
                                              вот, к примеру, innerHTML тоже не нативная, но тем не менее реалии, зачастую, делают свои стандарты.
                                              • 0
                                                Кто Вам сказал что это свойство не нативное?
                                              • НЛО прилетело и опубликовало эту надпись здесь
                                          • –4
                                            Читайте маны, товарисч. Для выборки элементов с точкой в имени ее необходимо будет экранировать $('div\\.button')
                                            • НЛО прилетело и опубликовало эту надпись здесь
                                          • +4
                                            Совет не про производительность, а просто нотация, чтобы отличать джиквери объекты от обычных: начинать название элемента с $.

                                            var $inputs = $('#myForm input');
                                            • –1
                                              а я предпочитаю так называть глобальные переменные
                                            • 0
                                              А какже context? $('#elmId', context)
                                              • 0
                                                можно и так: $(context).find('child')

                                              • –2
                                                спасибо, никогда не задумывался над этим
                                                • 0
                                                  А еще += очень медленная операция =) лучше с массивом работать… Это к jQuery не относится, просто в манипуляциях с ДОМ Вы использовали эту штуку…
                                                  И я бы добавил отсебятыны: если просто нужно получить элемент по айди и сделать с ним что-то, то наверно даже быстрее будет найти их стандартными функциями, и отдать в $ найденный массив элементов, т.к jQuery не будет в этом случае парсить строку и разбирать на элементы для поиска а сразу поймет что получает набор элементов и просто добавит массиву своих методов
                                                  • 0
                                                    По id массив не ищут, ибо на то он и id, что уникальный. А скорость работы += в 99.9...9% случаев вообще ни на что не влияет, в тысячу раз больше выиграете, если от той же jquery откажетесь :)
                                                    • 0
                                                      В голове крутилось «по айди или имени тега», но дописал только первую часть =) опечатка, скажем так
                                                      • +1
                                                        вы не поверите, но += может очень даже сильно повлиять из-за постоянного захламления памяти и вызова GC.
                                                    • 0
                                                      Немного добавлю от себя (правда, это больше касается не эффективности, а удобства разработки).

                                                      Названия всех jQuery-объектов можно начинать с буквы «j», например,
                                                      jMyElement, jInputs, jMyList и так далее.
                                                      Хорошо помогает ориентироваться, и не путать обычные DOM-переменные с jQuery-обёртками.
                                                      • 0
                                                        Практика показывает что если человек работает с jQuery, то все DOM-переменные получаются с применением jQuery и значит они уже расширенные новыми методами
                                                        • 0
                                                          Практика показывает, точ человек успешно совмещает нативные методы DOM и jQuery-обертки, так что совет добавлять префикс переменным, в которые сохраняете jQuery-объекты, вполне себе ничего.
                                                          • 0
                                                            Обычно использование нативных методов увеличивает код, а с группами элементов и методов то нету, на много проще обернуть объект и обратаывать его с помошью используемой библиотеки
                                                      • –1
                                                        могу ошибаться, но вроде бы пункт 2 уже не актуален, джекуэри кеширует ранее найденные элементы сам
                                                        • 0
                                                          Нет, пока еще не кеширует
                                                        • 0
                                                          13 ноября 2009: «Как увеличить скорость работы jQuery скрипта»
                                                          http://habrahabr.ru/blogs/jquery/75103/

                                                          Даже начинается с того же примера. :) Видимо, основана на то же статье, что автор этой брал за основу.
                                                          • –1
                                                            var top_100_list = [...]; // содержимое новых элементов
                                                            var new_ul = "
                                                            • ' + top_100_list[i] + '
                                                            ";
                                                            $mylist.replaceWith(li_items);


                                                            В данном коде ошибка. Вместо li_items везде нужно использовать new_ul.
                                                            • 0
                                                              Забыл код в <pre> упаковать )

                                                              var top_100_list = [...]; // содержимое новых элементов
                                                              var new_ul = "<ul id='mylist'>"; // вставляемый html-текст
                                                              $mylist = $('#mylist'); // необходимый список
                                                              
                                                              for (var i=0; i< top_100_list.length; i++)
                                                                li_items += '<li>' + top_100_list[i] + '</li>';
                                                              new_ul += "</ul>";
                                                              $mylist.replaceWith(li_items);
                                                              



                                                              В данном коде ошибка. Вместо li_items везде нужно использовать new_ul.
                                                            • –8
                                                              Самый эффективный способ использования — вообще не использовать jQuery. В больших проектах все равно толку мало от write less, приходится все равно do more.
                                                              • 0
                                                                Не факт, как ни крути, а работать с группами элементов с помошью библиотек проще, да и написанной работы в них хватает чтоб избавить человека от лишних фантазий, да и протестированы библиотеки лучше чем вновь написанный код
                                                                • 0
                                                                  Работать с группами элементов при помощи библиотек проще. Но при чем тут JQ? Это всего лишь одна из библиотек, которая использует только определенный способ работы с элементами. На это я и акцентировал внимание. Мышление, заточенное только под JQ, не дает кодеру плюсов. Многие «суперскрипты» можно сделать без JQ в 10 раз проще и эффективнее

                                                                  Допустим, у вас есть задание, сделать переключатель видимости элемента

                                                                  Состояние 1

                                                                  [показать контент]

                                                                  Состояние 2
                                                                  [спрятать контент]
                                                                  | Контент блока 1 |

                                                                  Как вы будете реализовывать данный код?
                                                                  • 0
                                                                    Причем тут задание? Человек не знаючий чистый JS не будет нормально работать с jQ, это очевидно, просто в библиотеках полно кода который уже написали, и его не надо будет писать заново, но он может помочь
                                                                    • 0
                                                                      Прошу еще раз внимательно перечитать мое сообщение. Я разве спорю с хоть одним из ваших очевидных постулатов? Я спорю с тем, что jQ не дает выигрыша при использовании в больших проектах. И проблема тут не в готовости кода, а в подходах, которые используются в jQ. Они убивают желание думать своей головой, а не абстракциями фреймворка. И пример я приводил сугубо для того, чтобы показать ошибочность логики построения решения.
                                                                      • 0
                                                                        1 — Ваш пример глупый
                                                                        2 — Библиотеки не убивают желание думать головой, а лишь избавляют от некоторых проблем
                                                                        3 — пишите на Си вебсайты, там надо больше думать

                                                                        как-то так
                                                                        • 0
                                                                          1. Обоснование я услышу?
                                                                          2. Библиотека обладает определенным функционалом. Использование функционала ограничивает варианты решения задач.
                                                                          3. А Си при чем тут?
                                                                          • 0
                                                                            1 Напишите решение на чистом JS, я вам приведу более компактное решение на любой библиотеке
                                                                            2 Функционал библиотек при желании можно увеличить, для этого нужна всего одна строка + своя функция, и она будет работать как с одним элементом, так и с набором данных
                                                                            3 Си заставит вас от мнения «убивают желание думать своей головой», потому как заставит Вас думать
                                                                            • –2
                                                                              Не проблема

                                                                              <div>
                                                                              <a href="#" onclick=«this.parentNode.className='swapOn'» class=«swapBlock1»>[показать контент]</a>
                                                                              <a href="#" onclick=«this.parentNode.className=''» class=«swapBlock2»>[спрятать контент]</a>
                                                                              <div class=«swapBlock2»>Контент блока 1</div>
                                                                              </div>

                                                                              .swapBlock2, .swapOn .swapBlock1 {display: none }
                                                                              .swapOn .swapBlock2 { display: block }

                                                                              Приводите более компактное решение. Я закрою глаза, что фреймворк весит немало килобайт.
                                                                              • +1
                                                                                Нативный инлайновый JS-код, который ещё и сбрасывает хеш страницы при клике на ссылки… фу, бяка.
                                                                                • –1
                                                                                  Если вы про недостающий return false, то засчитаю как повод придраться.

                                                                                  Я много слышал восторженных откликов про ненавязчивый JS, но на простой вопрос, на каком элементе в данной конструкции навешен обработчик click, мне никто и не ответил

                                                                                  <ul class=«menu»>
                                                                                  <li class=«menuItem»><span class=«menuTitle»>Menu item1</span></li>
                                                                                  <li class=«menuItem»><span class=«menuTitle»>Menu item2</span></li>
                                                                                  </ul>


                                                                                  Вот открываете вы файл, и не можете ответить на столь простой вопрос. Для ответа на этот простой вопрос, вам необходимо открывать как минимум еще один файл. Иногда даже больше. Эффективность поиска ошибки просто на высоте! Непонятно, почему круто, но все говорят, что это несомненно круто.
                                                                                  • 0
                                                                                    Спорить я с вами не буду по поводу необходимости качественных библиотек для JS.
                                                                                    Но ваше «не понятно» говорит лишь о том, что вам это непонятно, но как аргумент не живёт. Особенно для полностью динамических приложений. И не дай боже мне открыть подобный «файл»!
                                                                                    • 0
                                                                                      Полностью динамические приложения? Покажите, с удовольствием посмотрю.
                                                                                      • 0
                                                                                        Clipperz подойдёт?
                                                                                        • 0
                                                                                          Подойдет. Я такие три года назад делал. Ничего военного нет.
                                                                                • 0
                                                                                  это говно, а не решение.
                                                                                  • 0
                                                                                    У него есть недостатки, это несомнено, но вы сначала подумайте над достоинствами. Хаять можно любой код, даже ваш
                                                                                    • 0
                                                                                      я не могу увидеть достоинства в скрипте, вписанном в html атрибуты, завязанный на классы 1,2,3. если а 1000 элементов?

                                                                                      если в Вашем примере врапперу проставить класс .toggler (ниже Вы сами пишите про масштабируемость), обоим ссылкам поставить класс .toggle, вторую ссылку и блок с контентом обернуть в div.content, то, убрав все остальные классы имеем:

                                                                                      $('.toggler .toggle').click(function() {
                                                                                      $(this).parents('.toggler:first').toggleClass('hidden');
                                                                                      });

                                                                                      И все. Ну и стили:

                                                                                      .hidden .content, .toggler .toggle { display: none; }
                                                                                      .hidden .toggle, .content .toggle { display: inline; }
                                                                                      .toggle { cursor: pointer; } /* :) */
                                                                                      • 0
                                                                                        Классов всего два. Потому как состояния всего два: видимые элементы и невидимые элементы.

                                                                                        Вы это потом мне же и описали, но другими словами.
                                                                                  • 0
                                                                                    <div>
                                                                                    <a href="#" id=«shoHide»>Показать/скрыть контент</a>
                                                                                    <div class=«swapBlock2» id=«content»>Контент блока 1</div>
                                                                                    </div>
                                                                                    $('#showHide').click(
                                                                                    function(){
                                                                                    $('#content').toggle()
                                                                                    }
                                                                                    )
                                                                                    

                                                                                    Я очень не люблю ЖС в тегах, на много проще им пользоваться в одном файле
                                                                                    Пример не такой как Вы хотели, но я думаю Вы суть поняли. Чтоб надпись «показать/скрыть контент» менялась, добавится всего одна строчка.
                                                                                    Код с библиотекой приятней и понятней, и нет каши между HTML и JS
                                                                                    • 0
                                                                                      Ха, скопируйте свой код два раза. Упс. Масштабируемость на высоте.
                                                                                      • 0
                                                                                        Зачем мне его копировать 2 раза?
                                                                                        $('#showHide').click(
                                                                                            function(){
                                                                                                $(this).parent.toggleClass('swapOn')
                                                                                            }
                                                                                        )

                                                                                        Так Вас устроит?
                                                                                        • –2
                                                                                          Потому что код можно повторно использовать. Ваш код нельзя.
                                                                                          • 0
                                                                                            Вполне можно:
                                                                                            $('#showHide, #otherShowHide, #thirdShowHide').click(
                                                                                                function(){
                                                                                                    $(this).parent().toggleClass('swapOn')
                                                                                                }
                                                                                            )

                                                                                            Я только что скопировал свой код 3 раза, я могу массив айдишников сделать, я могу всем нужным элементам дать бутафорский класс и по нему показывать скрывать… Вы такого не можете на чистом JS, вернее можете, но это займет время и код.
                                                                                            • 0
                                                                                              Массив айдишников требует менеджера айдишников, чтобы ваш код продолжал функционировать. Мне стоит добавить всего одну примитивную функцию, которая бы искала парента по имени класса, и на этом простом приеме я бы сделал огромный шаг к масштабированию кода. Еще понадобится примитивная функция, которая бы добавляла имя класса или удаляла его у ноды без глобальной перезаписи.
                                                                                              Сделав всего две простые функции, я могу их потом использовать везде, много раз.
                                                                                              • 0
                                                                                                // put here selector to enable folding
                                                                                                var items = ['#id1', '#id2', '#id3', '#id4']
                                                                                                $(items.join(', ')).click(
                                                                                                    function(){
                                                                                                        $(this).parent().toggleClass('swapOn')
                                                                                                    }
                                                                                                )

                                                                                                Еще варианты? Я сделал универсальный менеджер для сворачивания элементов
                                                                                                • 0
                                                                                                  А теперь подумайте, как использовать ваш код при том же подходе, что и в Clipperz
                                                                                                  • 0
                                                                                                    Если честно, я не понял о чем Вы.
                                                                                                    • 0
                                                                                                      О том, что менеджер идентификаторов должен пронизывать весь ваш код, да еще и код серверных скриптов. Там все данные показываются на одной странице, поэтому нужно следить за тем, чтобы разные модули не пытались использовать одинаковые идентификаторы, что приведет к просто непредсказуемуму результату. Вы будете наворачивать код на своей стороне, на стороне сервера, только ради идентификаторов? Это очень плохая затея, которая все равно закончится багами.
                                                                                                      • 0
                                                                                                        А не проще идентификаторы давать вида:
                                                                                                        modulename_blockname? они не будут пересекаться и будет понятно что куда относится
                                                                                                        • 0
                                                                                                          :) Это помогает, но не всегда.
                                                                                                          В одном и том же модуле могут быть два одинаковых элемента.
                                                                                                          Проблема с префиксами поджидает еще в другом месте. Если два модуля будут использовать код третьего, то они получат… два одинаковых идентификатора от третьего модуля. Или получат два разных, а нужно использовать один одинаковый.

                                                                                                          Проблема кроется в самом факте наличия идентификатора. В проектах с одной страницей и подгружаемыми модулями нужно избавляться от них. А это уже другая философия
                                                                                                          • +1
                                                                                                            У вас плохой код, я это могу определить даже не видя его. Раз на стадии проектирования такой каламбур, то код небось тоже такой же шифрованный.
                                                                                                            Если я показываю блок «users» то он должен у меня быть один, и ниипет меня там кто что использует, другой модуль поиспользовал мой, и вывед все то что наиспользовал со своим идентификатором «othermodule». Мне не нужна каша в коде
                                                                                                            • 0
                                                                                                              В общем мы полезли не в ту степь. Я предлагаю Вам идеальный вариант для фолдинга: делаем класс болванку, и используем мой код, если нужно сворачивать блок, даем ему этот класс, все, проблемы нет, можно без всяких конфликтов использовать мой код с пустым классом. Если вас не устраивает это решение, используйте свое дальше, а я буду использовать све, на этом и разойдемся
                                                                                                              • 0
                                                                                                                Вы в глаза не видели моего кода, но уже осмеливаетесь заявлять, что он плохой? Каша не у меня в голове, каша возникает у многих программистов, когда они не видят проблем будущего.
                                                                                        • 0
                                                                                          Второй вопрос туда же. Что вы будете делать, когда вам вдруг нужно будет включать не один блок, а два?
                                                                                          • 0
                                                                                            И третий вопрос, вы не выполнили условие задания, вы сделали одну кнопку, а нужно две.
                                                                                            • 0
                                                                                              Зачем мне кнопка «показать блок» когда блок показан?
                                                                                              • 0
                                                                                                Внимательно изучите исходное задание.
                                                                                                • 0
                                                                                                  Я разработчик а не бот, я могу предложить вариант лучше и заказчик с 99% вероятности согласится со мной в даной ситуации
                                                                                                  • 0
                                                                                                    Вот и подтверждение того, что вам проще изменить задачу под возможности фреймворка, чем реализовать 1 к 1 поставленную задачу.
                                                                                                    • 0
                                                                                                      Нет, задачу я меняю не под возможности фреймворка, а под удобство использования. Хорошее UI — залог удобства использования проекта в целом. Библиотека здесь абсолютно ни при чем, второй код будет прекрасно работать с вашим примером
                                                                                                      • 0
                                                                                                        Так вот я предложил вам пример хорошего UI, который четко идентифицирует текущее состояние элемента, а вы предложили некий сомнительный вариант, который не рассказывает мне вообще, в каком состоянии я нахожусь. Потому что невидимость блока может быть банальной ошибкой.
                                                                                                        • 0
                                                                                                          Ошибок в коде не должно быть
                                                                                                          • 0
                                                                                                            Но вы не можете гарантировать 100%, по какой именно причине может возникнуть данная ошибка. Это может быть банальный баг в CSS
                                                                          • +5
                                                                            • 0
                                                                              это что за скриншот? о0
                                                                              • 0
                                                                                Полагаю, что Isis облегчил taliban жизнь, заблокировав для него habrahabr.ru/blogs/jquery/
                                                                                • +1
                                                                                  ясно, синдром вахтёра…
                                                                                  • –1
                                                                                    Я бы это назвал синдромом неудачника. Все, кто ругают любимый фреймворк (браузер, OS, марку пива) — враги по умолчанию. Слушая врагов — подрываешь веру в любимую фигнюшечку.
                                                                              • 0
                                                                                вот и поговорили [х]
                                                                              • 0
                                                                                Ага, ведь это же так увлекательно — раз за разом копипастить/писать с нуля обёртки для attachEvent/addEventListener, getElement(s)By(Id|ClassName|TagName)/querySelector и ещё 100500 API. Потом заботливо обвешивать полученную тамагочу Только Нужным Функционалом и кропотливо затачивать под старые и новые прибабахи браузеров. Ведь сроки у нас резиновые, а усилия по выращиванию нового питомца обязательно будут оценены по достоинству.
                                                                                • +1
                                                                                  Читайте между строк. Никто не мешает вам сделать набор утилит по решению ваших задач. Большинство функционала JQ не нужно для решения 80% задач. Но пост не об этом. Вы должны заботиться не только про стандартизацию разработки, но и за уменьшение ошибок в будущем коде, уменьшение стоимости будущей разработки. Вы должны эффективно использовать инструмент, а не надеяться, что наличие инструмента уже добавляет вам эффективности.
                                                                                  • 0
                                                                                    Никто не мешает вам сделать набор утилит по решению ваших задач.
                                                                                    Зачем, если уже 90% моих нужд покрывают готовые решения вроде %jsframeworkname%, ещё 9% прикручивается плагинами, а остальные 1% дописывается руками?
                                                                                    Вы должны эффективно использовать инструмент, а не надеяться, что наличие инструмента уже добавляет вам эффективности.
                                                                                    не спорю
                                                                                    Вы должны заботиться не только про стандартизацию разработки, но и за уменьшение ошибок в будущем коде, уменьшение стоимости будущей разработки.
                                                                                    скажите, кто лучше заботится об отсутствии ошибок и уменьшении стоимости разработки — Вася Пупкин (единственный разработчик/пользователь самодельного недофреймворка, в котором есть Только То, Что Нужно) или армия пользователей (они же тестеры, они же контрибьюторы) %jsframeworkname%?
                                                                                    • 0
                                                                                      Скажите, а защищает ли вас фреймворк от ошибок, которые допускает разработчик при использовании этого самого фреймворка?
                                                                                      • 0
                                                                                        Если разработчик не внимателен, то фреймворк не стоит винить
                                                                                        • 0
                                                                                          Это как раз подтверждает мой постулат, что даже сколь угодно стабильный фреймворк, который разрабатывают тысячи разработчиков, проверяет миллион тестеров, не избавляет от ошибок. И самое интересное, не избавляет от ошибок архитектуры.
                                                                                          • +1
                                                                                            Вы исковеркали мои слова: Если разработчик баран — то никакой фреймворк ему не поможет, если разработчик с головой дружит, то фреймворк поможет ему сэкономить время и код
                                                                                        • 0
                                                                                          А разве это возможно?
                                                                                      • +1
                                                                                        Ты не прав. Я как-то работал с мегабайтами JS кода, сокращенными в несколько раз при адаптации jQuery.
                                                                                        • 0
                                                                                          Я работаю с кодом, который был написан еще 3 года назад, используется по всему проекту, и ни разу еще не был переписан. Повтор использования кода достигает от 60 до 90%. Вы сократили в несколько раз объем кода, но сократили ли вы одновременно с этим количество ошибок? Достигли большей понимаемости кода? Проще ли вам изменять продукт с этим кодом? Остался ли уровень количества переделок на том же уровне, или стало лучше?

                                                                                          Подумайте над эффективностью инструментов.
                                                                                      • +1
                                                                                        я для ЛибКанваса так и делал первую неделю. Потом посмотрел, понял, что я изобретаю Мутулз и плюнул.
                                                                                        Где-где, а в ЖС библиотеки сейчас прекрасны и нету смысла их не использовать
                                                                                  • +6
                                                                                    1.2 Пункт не верен, в данном примере $('#id input') будет работать медленнее чем просто $('input'), для ускорения необходимо указывать контекст, для этого и служит второй параметр: $('input', $('#id')[0]), или $('#id').find('input');

                                                                                    1.3 Тоже неверное рассуждение, будут найдено множество .button потом к нему применен фильтр по тэгу, сам же селектор вида tag.class будет работать быстрее только относительно браузеров у которых нет поддержки функции getElementsByClassName (IE <= 7 кажись)

                                                                                    2. jQuery не кеширует селекторы, для поиска используется движок Sizzle — в нем нет механизма кеширования.

                                                                                    Еще хороший пример:

                                                                                    $('#selector').click(function(){
                                                                                         $(this).find('.class')....;
                                                                                    });


                                                                                    Лучше

                                                                                    $('#selector').click(function(){
                                                                                         $('.class', this)....;
                                                                                    });


                                                                                    4. Делегирование описано без упоминания метода delegate?
                                                                                    • –1
                                                                                      1.2. ты померил чтобы так утверждать?
                                                                                      • +1
                                                                                        Мне достаточно знать как работает Sizzle, чтобы так утверждать.
                                                                                        • 0
                                                                                          и как он работает?
                                                                                          • 0
                                                                                            Посмотрите в исходники — узнаете.

                                                                                            В заметке хватает вранья. Автор, видимо, не смотрел правила разбора селекторов в JQuery и просто скомпилировал другие заметки (с выдуманными фактами) в эту.
                                                                                        • 0
                                                                                          Насколько помню к релизу jQuery 1.4 Sizzle оптимизировали под часто используемые селекторы, в том числе и с #id в начале — они должны приводить к поиску в контексте
                                                                                          • 0
                                                                                            Такое может быть. В этом случае лучше указывать версию JQuery, так как 1.3 много где используется, и оптимизируя без учета версии получим наоборот тормоза.
                                                                                            • 0
                                                                                              Посмотрел в исходниках, проверка на id железная quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/ (html или id), так что оптимизации селекторов с #id не нашел.
                                                                                              • 0
                                                                                                Этот код из jQuery, а копать надо в Sizzle
                                                                                                • +2
                                                                                                  В самом Sizzle имеется проверка и оптимизация на #id в начале селектора

                                                                                                  // Take a shortcut and set the context if the root selector is an ID
                                                                                                  // (but not if it'll be faster if the inner selector is an ID)
                                                                                                  if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
                                                                                                  Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length — 1]) ) {
                                                                                                  var ret = Sizzle.find( parts.shift(), context, contextXML );
                                                                                                  context = ret.expr? Sizzle.filter( ret.expr, ret.set )[0]: ret.set[0];
                                                                                                  }

                                                                                                  Т.е. сперва ищется элемент по id, затем он становится контекстом, в котором происходит дальнейший поиск. Т.е. конструкция вида $('#id tagName') работает после разбора селектора как $('tagName', '#id'), однако тратится какое-то время на сам разбор селектора с помощью регулярных выражений и другие операции. Можете протестировать — скорость отличаться будет, ну, грубо на несколько процентов, в зависимости от сложности самой выборки и т.п.
                                                                                                  Но это относится, например, к FF 3.0, где нет нативной поддержки querySelectorAll.

                                                                                                  Другое дело, когда вы используете «современный» браузер аля Chrome или FF версии 3.6+, где при указании селектора вида $('#id tagName') за работу берется сам движок браузера, который делает по понятным причинам это достаточно быстро. Однако если вы в современном браузере укажете $('tagName', '#id'), то тут уже в работу пойдет Sizzle, который как бы он там не оптимизировал селекторы, все равно работает медленнее, чем querySelectorAll.

                                                                                                  Вывод: «старый» браузер — быстрее $('tagName', '#id'), новый — быстрее $('#id tagName').
                                                                                                  Можете просто элементарно замерить скорость выборки на страничке.
                                                                                                  • 0
                                                                                                    Надо было страничку обновить :(
                                                                                                    Насчет же querySelectorAll — то лучше бить запрос на куски, если есть сомнения, что querySelectorAll его не прохавает, к примеру при использовании кастомных фильтров.
                                                                                                    • +1
                                                                                                      Да, во всём нужен разумный подход. Но это уже специфический вопрос очень тонкой оптимизации, когда экономия идёт на миллисекунды, мы не будем сейчас об этом.

                                                                                                      Сам я кастомные фильтры не люблю, вернее, не использую почти никогда, потому что нет необходимости, в большинстве случаев получается все делать без них — простота — залог успеха.
                                                                                                      • 0
                                                                                                        Полностью согласен, надо будет как-нить и самому аналогичную статью написать, там и будем ломать копья…
                                                                                                  • 0
                                                                                                    Накопал:
                                                                                                    // Take a shortcut and set the context if the root selector is an ID
                                                                                                    // (but not if it'll be faster if the inner selector is an ID)
                                                                                                    if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
                                                                                                    	Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
                                                                                                    	var ret = Sizzle.find( parts.shift(), context, contextXML );
                                                                                                    	context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
                                                                                                    }
                                                                                                    


                                                                                                    Если ищем в рамках контекста Document, и первым идет #id (и не идет при этом последним), то в качестве контекста таки будет использоваться элемент #id
                                                                                                • 0
                                                                                                  Как показала практика, переход с 1.3 на 1.4 совершенно безболезненнен обычно. Ну и обычно подразумевается актуальная версия, если не указана иная
                                                                                          • +2
                                                                                            У вас дельные замечания.

                                                                                            Единственное п. 2 разницы между $(this).find и $('.class', this) нет.

                                                                                            // HANDLE: $(expr, context)
                                                                                            // (which is just equivalent to: $(context).find(expr)
                                                                                            } else {
                                                                                            return jQuery( context ).find( selector );
                                                                                            }
                                                                                            • 0
                                                                                              тем более, $(this).find('.class') читается куда лучше
                                                                                              • 0
                                                                                                Да, действительно, не доглядел…
                                                                                              • 0
                                                                                                > в данном примере $('#id input') будет работать медленнее чем просто $('input')
                                                                                                судя по этой статье vremenno.net/js/how-to-test-and-optimize-scripts/ всё таки будет быстрей ) хотя возможно так: $('#id').find('input'); будет ещё быстрей.
                                                                                              • 0
                                                                                                Для 4 существует live и delegate
                                                                                                • 0
                                                                                                  «Как известно, стандартные события javascript, вызванные на каком-либо элементе, затем вызываются на всех его потомках» исправьте на «предках».
                                                                                                  • 0
                                                                                                    не знаю автор тырил где-то статью эту по частям, или сам натестился )
                                                                                                    но вот есть например такая статья habrahabr.ru/blogs/jquery/52201/
                                                                                                    ей уже полтора года
                                                                                                    • 0
                                                                                                      А кэшировать кто будет?
                                                                                                      jQuery.root = jQuery(document);
                                                                                                      $$ = function(sel) {
                                                                                                      return jQuery.root.find(sel);
                                                                                                      };

                                                                                                      И не надо лишний раз создавать объект jQuery, во многих местах можно на чистом js писать. Простейший пример:
                                                                                                      $('#spam').bind('click', function() {
                                                                                                      $(this).attr('id', 'eggs');
                                                                                                      });

                                                                                                      медленнее, чем
                                                                                                      $('#spam').bind('click', function() {
                                                                                                      this.id = 'eggs';
                                                                                                      });
                                                                                                      • 0
                                                                                                        Пункт 4.
                                                                                                        $('#myList').click(function(event){
                                                                                                        $(event.target).addClass('clicked'); // добавим нажатому элементу класс clicked
                                                                                                        });


                                                                                                        в КОРНЕ непрактичен. Вот вам пример разметки выпадающего меню с подпунктами:
                                                                                                        <ul id="#myList">
                                                                                                           <li>
                                                                                                              <a> Menu 1 </a>
                                                                                                           </li>
                                                                                                           <li>
                                                                                                              <a> Menu 2 </a>
                                                                                                           </li>
                                                                                                           <li>
                                                                                                              Menu 3
                                                                                                        	<ul>
                                                                                                        	   <li>
                                                                                                        		  <a> Submenu 3-1 </a>
                                                                                                        	   </li>
                                                                                                        	</ul>
                                                                                                        	</li>
                                                                                                        </ul>
                                                                                                        
                                                                                                        


                                                                                                        Кликнуть можно на:
                                                                                                        #myList > ul
                                                                                                        #myList > ul > li
                                                                                                        #myList > ul > li > a
                                                                                                        #myList > ul > li > ul


                                                                                                        event.target может стать чем-угодно, надо добавлять геморроя с проверкой. А выгода от производительности ничтожна.
                                                                                                        • 0
                                                                                                          Насчет пункта 4:
                                                                                                          А не проще использовать $('#myList li').live('click', function(){$(this).addClass('clicked')});?
                                                                                                          Он навешивает всего один обработчик на страницу. И сам определяет элемент по которому кликнули. Скорость работы такая же как и у вас только все логично и без проверок.

                                                                                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.