Статьи

14 полезных советов, заметок и рекомендаций jQuery

Если есть что-то плохое в jQuery, так это то, что начальный уровень настолько низок, что привлекает тех, кто не знает ни грамма JavaScript. Теперь, с одной стороны, это фантастика. Однако, с другой стороны, это также приводит к тому, что, откровенно говоря, возникает отвратительно плохой код (некоторые из которых я написал сам!).

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


Важно помнить, что большинство методов возвращают объект jQuery. Это очень полезно и позволяет использовать функции цепочки, которые мы используем так часто.

1
2
3
4
$someDiv
  .attr(‘class’, ‘someClass’)
  .hide()
  .html(‘new stuff’);

Зная, что объект jQuery всегда возвращается, мы можем использовать его для временного удаления лишнего кода. Например, рассмотрим следующий код:

1
2
var someDiv = $(‘#someDiv’);
someDiv.hide();

Причина, по которой мы « someDiv » местоположение элемента someDiv заключается в том, чтобы ограничить число раз, которое нам приходится проходить через DOM для этого элемента, до одного раза.

Код выше прекрасно; тем не менее, вы могли бы так же легко объединить две линии в одну, достигая того же результата.

1
var someDiv = $(‘#someDiv’).hide();

Таким образом, мы все еще someDiv элемент someDiv , но метод, как мы узнали, также возвращает объект jQuery — на который затем ссылается переменная someDiv .


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

Одним из таких решений является использование метода find() , когда это возможно. Ключ не заставляет jQuery использовать движок Sizzle, если в этом нет необходимости. Конечно, будут времена, когда это невозможно — и это нормально; но, если вам не нужны дополнительные накладные расходы, не ищите их.

1
2
3
4
5
// Fine in modern browsers, though Sizzle does begin «running»
$(‘#someDiv p.someClass’).hide();
 
// Better for all browsers, and Sizzle never inits.
$(‘#someDiv’).find(‘p.someClass’).hide();

В последних современных браузерах есть поддержка QuerySelectorAll , которая позволяет передавать CSS-подобные селекторы без необходимости в jQuery. Сам jQuery проверяет и эту функцию.

Однако более старые браузеры, а именно IE6 / IE7, по понятным причинам не обеспечивают поддержку. Это означает, что эти более сложные селекторы запускают полный движок Sizzle в jQuery, который, хотя и гениален, все же приносит немного больше накладных расходов.

Sizzle — это блестящая масса кода, которую я никогда не пойму. Однако в предложении он сначала берет ваш селектор и превращает его в «массив», состоящий из каждого компонента вашего селектора.

1
2
// Rough idea of how it works
 [‘#someDiv, ‘p’];

Затем справа налево начинается расшифровка каждого элемента с помощью регулярных выражений. Это также означает, что крайняя правая часть вашего селектора должна быть как можно более конкретной — например, id или имя тега.

Итог, когда это возможно:

  • Сделайте ваши селекторы простыми
  • Используйте метод find() . Таким образом, вместо использования Sizzle, мы можем продолжать использовать встроенные функции браузера.
  • При использовании Sizzle максимально оптимизируйте самую правую часть вашего селектора.

Также можно добавить контекст для ваших селекторов, например:

1
$(‘.someElements’, ‘#someContainer’).hide();

Этот код предписывает jQuery обернуть коллекцию всех элементов классом someElements — потомками someContainer — в jQuery. Использование контекста — это полезный способ ограничения обхода DOM, хотя вместо этого jQuery использует метод find .

1
2
3
$(‘#someContainer’)
  .find(‘.someElements’)
  .hide();
1
2
3
4
5
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
   return jQuery( context ).find( selector );
}

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

1
2
3
4
$(‘#someAnchor’).click(function() {
    // Bleh
    alert( $(this).attr(‘id’) );
});

Если нам нужен только объект jQuery для доступа к атрибуту id тега привязки, это расточительно. Лучше придерживаться «сырого» JavaScript.

1
2
3
$(‘#someAnchor’).click(function() {
    alert( this.id );
});

Обратите внимание, что есть три атрибута, которые всегда должны быть доступны через jQuery: «src», «href» и «style». Эти атрибуты требуют использования getAttribute в более старых версиях IE.

1
2
3
4
5
6
7
8
9
// jQuery Source
var rspecialurl = /href|src|style/;
// …
var special = rspecialurl.test( name );
// …
var attr = !jQuery.support.hrefNormalized && notxml && special ?
    // Some attributes require a special call on IE
    elem.getAttribute( name, 2 ) :
    elem.getAttribute( name );

Еще хуже процесс многократного запроса DOM и создания нескольких объектов jQuery.

1
2
3
$(‘#elem’).hide();
$(‘#elem’).html(‘bla’);
$(‘#elem’).otherStuff();

Надеюсь, вы уже знаете, насколько неэффективен этот код. Если нет, то все в порядке; мы все учимся Ответ заключается либо в #elem цепочки, либо в «кэшировании» местоположения #elem .

01
02
03
04
05
06
07
08
09
10
11
// This works better
$(‘#elem’)
  .hide()
  .html(‘bla’)
  .otherStuff();
 
// Or this, if you prefer for some reason.
var elem = $(‘#elem’);
elem.hide();
elem.html(‘bla’);
elem.otherStuff();

Слушать, когда документ готов для манипуляции, просто смешно с jQuery.

1
2
3
$(document).ready(function() {
    // let’s get up in heeya
});

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

1
2
3
$(function() {
    // let’s get up in heeya
});

Хотя последний является несколько менее читаемым, два фрагмента выше идентичны. Не веришь мне? Просто проверьте исходный код jQuery.

1
2
3
4
5
// HANDLE: $(function)
// Shortcut for document ready
if ( jQuery.isFunction( selector ) ) {
    return rootjQuery.ready( selector );
}

rootjQuery — это просто ссылка на корневой jQuery(document) . Когда вы передаете селектор в функцию jQuery, он определяет, какой тип селектора вы передали: строка, тег, идентификатор, функция и т. Д. Если функция была передана, jQuery затем вызовет ее метод ready() и передаст ваш анонимная функция в качестве селектора.


При разработке кода для распространения всегда важно компенсировать любое возможное столкновение имен. Что произойдет, если какой-нибудь скрипт, импортированный после вашего, также имеет функцию $ ? Плохие вещи!

Ответ заключается в том, чтобы либо вызвать jQuery noConflict() , либо сохранить свой код в самовозглашающейся анонимной функции, а затем передать ей jQuery.

1
2
3
4
5
6
var j = jQuery.noConflict();
// Now, instead of $, we use j.
j(‘#someDiv’).hide();
 
// The line below will reference some other library’s $ function.
$(‘someDiv’).style.display = ‘none’;

Будьте осторожны с этим методом и старайтесь не использовать его при распространении вашего кода. Это действительно смутило бы пользователя вашего скрипта! 🙂

1
2
3
(function($) {
    // Within this function, $ will always refer to jQuery
})(jQuery);

Последние парни внизу вызывают функцию автоматически — function(){}() . Однако когда мы вызываем функцию, мы также передаем jQuery, который затем представляется как $ .

1
2
3
4
5
jQuery(document).ready(function($) {
 // $ refers to jQuery
});
 
// $ is either undefined, or refers to some other library’s function.

Помните — jQuery — это просто JavaScript. Не думайте, что он способен компенсировать ваше плохое кодирование. 🙂

Это означает, что так же, как мы должны оптимизировать такие вещи, как JavaScript for операторов, то же самое верно для each метода jQuery. А почему бы и нет? Это просто вспомогательный метод, который затем создает закадровый оператор for .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// jQuery’s each method source
    each: function( object, callback, args ) {
        var name, i = 0,
            length = object.length,
            isObj = length === undefined ||
 
        if ( args ) {
            if ( isObj ) {
                for ( name in object ) {
                    if ( callback.apply( object[ name ], args ) === false ) {
                        break;
                    }
                }
            } else {
                for ( ; i < length; ) {
                    if ( callback.apply( object[ i++ ], args ) === false ) {
                        break;
                    }
                }
            }
 
        // A special, fast, case for the most common use of each
        } else {
            if ( isObj ) {
                for ( name in object ) {
                    if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
                        break;
                    }
                }
            } else {
                for ( var value = object[0];
                    i < length && callback.call( value, i, value ) !== false;
            }
        }
 
        return object;
    }
1
2
3
someDivs.each(function() {
    $(‘#anotherDiv’)[0].innerHTML += $(this).text();
});
  1. Ищет anotherDiv для каждой итерации
  2. Получает свойство innerHTML дважды
  3. Создает новый объект jQuery, все для доступа к тексту элемента.
1
2
3
4
5
6
7
var someDivs = $(‘#container’).find(‘.someDivs’),
      contents = [];
 
someDivs.each(function() {
    contents.push( this.innerHTML );
});
$(‘#anotherDiv’).html( contents.join(») );

Таким образом, в each методе (for) единственная задача, которую мы выполняем, — это добавление нового ключа в массив … вместо того, чтобы запрашивать DOM, дважды innerHTML свойство innerHTML элемента и т. Д.

Этот совет больше основан на JavaScript, а не на jQuery. Дело в том, чтобы помнить, что jQuery не компенсирует плохое кодирование.

Пока мы на этом, другой вариант для таких ситуаций — использовать фрагменты документа.

01
02
03
04
05
06
07
08
09
10
11
var someUls = $(‘#container’).find(‘.someUls’),
    frag = document.createDocumentFragment(),
    li;
     
someUls.each(function() {
    li = document.createElement(‘li’);
    li.appendChild( document.createTextNode(this.innerHTML) );
    frag.appendChild(li);
});
 
$(‘#anotherUl’)[0].appendChild( frag );

Ключевым моментом здесь является то, что существует несколько способов выполнения простых задач, подобных этой, и каждый из них имеет свои собственные преимущества в производительности от браузера к браузеру. Чем больше вы будете придерживаться jQuery и изучать JavaScript, тем чаще вы будете ссылаться на собственные свойства и методы JavaScript. И если это так, это фантастика!

jQuery обеспечивает удивительный уровень абстракции, которым вы должны воспользоваться, но это не значит, что вы вынуждены использовать его методы. Например, в приведенном выше примере фрагмента мы используем each метод jQuery. Если вы предпочитаете использовать оператор for или while , это тоже нормально!

Учитывая все вышесказанное, имейте в виду, что команда jQuery значительно оптимизировала эту библиотеку. Дебаты о each() jQuery и нативном for оператора являются глупыми и тривиальными. Если вы используете jQuery в своем проекте, сэкономьте время и используйте их вспомогательные методы. Вот для чего они здесь! 🙂


Если вы только сейчас начинаете копаться в jQuery, различные методы AJAX, которые он делает доступными для нас, могут показаться немного устрашающими; хотя они не нуждаются. Фактически, большинство из них являются просто вспомогательными методами, которые направляют непосредственно к $.ajax .

  • получить
  • getJSON
  • Почта
  • Аякса

В качестве примера давайте рассмотрим getJSON , который позволяет нам выбирать JSON.

1
2
3
4
$.getJSON(‘path/to/json’, function(results) {
    // callback
    // results contains the returned data object
});

За кулисами этот метод сначала вызывает $.get .

1
2
3
getJSON: function( url, data, callback ) {
    return jQuery.get(url, data, callback, «json»);
}

$.get компилирует переданные данные и снова вызывает «мастер» (своего рода) метод $.ajax .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
get: function( url, data, callback, type ) {
    // shift arguments if data argument was omited
    if ( jQuery.isFunction( data ) ) {
        type = type ||
        callback = data;
        data = null;
    }
 
    return jQuery.ajax({
        type: «GET»,
        url: url,
        data: data,
        success: callback,
        dataType: type
    });
}

Наконец, $.ajax выполняет огромный объем работы, чтобы мы могли успешно выполнять асинхронные запросы во всех браузерах!

Это означает , что вы также можете использовать метод $.ajax напрямую и исключительно для всех ваших запросов AJAX. Другие методы — это просто вспомогательные методы, которые в конечном итоге делают это. Так что, если хотите, вырежьте среднего человека. Это не существенная проблема в любом случае.

1
2
3
4
$.getJSON(‘path/to/json’, function(results) {
    // callback
    // results contains the returned data object
});
1
2
3
4
5
6
7
8
9
$.ajax({
    type: ‘GET’,
    url : ‘path/to/json’,
    data : yourData,
    dataType : ‘json’,
    success : function( results ) {
        console.log(‘success’);
    })
});

Итак, вы немного освоили JavaScript и узнали, что, например, для тегов привязки вы можете напрямую обращаться к значениям атрибутов:

1
2
3
4
5
var anchor = document.getElementById(‘someAnchor’);
 //anchor.id
// anchor.href
// anchor.title
// .etc

Единственная проблема в том, что это не работает, когда вы ссылаетесь на элементы DOM с помощью jQuery, верно? Ну, конечно, нет.

1
2
// Fails
var id = $(‘#someAnchor’).id;

Итак, если вам нужен доступ к href (или к любому другому нативному свойству или методу), у вас есть несколько вариантов.

01
02
03
04
05
06
07
08
09
10
11
12
// OPTION 1 — Use jQuery
var id = $(‘#someAnchor’).attr(‘id’);
 
// OPTION 2 — Access the DOM element
var id = $(‘#someAnchor’)[0].id;
 
// OPTION 3 — Use jQuery’s get method
var id = $(‘#someAnchor’).get(0).id;
 
// OPTION 3b — Don’t pass an index to get
anchorsArray = $(‘.someAnchors’).get();
var thirdId = anchorsArray[2].id;

Метод get особенно полезен, поскольку он может преобразовать вашу коллекцию jQuery в массив.


Конечно, для огромного большинства наших проектов мы не можем полагаться только на JavaScript в таких вещах, как проверка или запросы AJAX. Что происходит, когда JavaScript отключен? По этой самой причине распространенным методом является определение того, был ли выполнен запрос AJAX с выбранным вами языком на стороне сервера.

jQuery делает это до смешного простым, устанавливая заголовок из метода $.ajax .

1
2
3
4
5
// Set header so the called script knows that it’s an XMLHttpRequest
// Only send the header if it’s not a remote XHR
if ( !remote ) {
    xhr.setRequestHeader(«X-Requested-With», «XMLHttpRequest»);
}

С этим установленным заголовком мы можем теперь использовать PHP (или любой другой язык) для проверки этого заголовка и действовать соответственно. Для этого мы проверяем значение $_SERVER['HTTP_X_REQUESTED_WITH'] .

1
2
3
function isXhr() {
  return $_SERVER[‘HTTP_X_REQUESTED_WITH’] === ‘XMLHttpRequest’;
}

Вы никогда не задумывались, почему / как вы можете использовать jQuery и $ взаимозаменяемо? Чтобы найти ответ, просмотрите исходный код jQuery и прокрутите до самого низа. Там вы увидите:

1
window.jQuery = window.$ = jQuery;

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

Чтобы исправить это, jQuery предоставляется глобальному объекту window , и в процессе также создается псевдоним — $ .


HTML5 Boilerplate предлагает изящную однострочную версию, которая будет загружать локальную копию jQuery, если по какой-то странной причине выбранный вами CDN не работает.

1
2
3
<!— Grab Google CDN jQuery.
<script src=»http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js»></script>
<script>!window.jQuery && document.write(‘<script src=»js/jquery-1.4.2.min.js»><\/script>’)</script>

Чтобы «сформулировать» приведенный выше код: если window.jQuery не определен, возможно, возникла проблема при загрузке сценария из CDN. В этом случае перейдите к правой стороне оператора && и вставьте скрипт, ссылающийся на локальную версию jQuery.


Примечание: jQuery.expr[':'] — это просто псевдоним для jQuery.expr.filters .


Начиная с jQuery 1.4, теперь мы можем передать только одну функцию методу hover . Раньше требовались оба метода: вход и выход .

1
2
3
4
5
$(‘#someElement’).hover(function() {
  // mouseover
}, function() {
 // mouseout
});
1
2
3
$(‘#someElement’).hover(function() {
  // the toggle() method can be used here, if applicable
});

Обратите внимание, что это не старая сделка против новой. Много раз вам все равно придется передавать две функции hover , и это вполне приемлемо. Однако, если вам нужно только переключить некоторый элемент (или что-то в этом роде), передача одной анонимной функции спасет несколько символов или около того!


Начиная с jQuery 1.4, теперь мы можем передавать объект как второй параметр функции jQuery. Это полезно, когда нам нужно вставить новые элементы в DOM. Например:

1
2
3
4
5
6
$(‘<a />’)
  .attr({
    id : ‘someId’,
    className : ‘someClass’,
    href : ‘somePath.html’
  });
1
2
3
4
5
$(‘</a>’, {
    id : ‘someId’,
    className : ‘someClass’,
    href : ‘somePath.html’
});

Это не только экономит несколько символов, но и делает код чище. В дополнение к атрибутам элементов, мы можем даже передавать специфические атрибуты и события jQuery, такие как click или text .


Спасибо за прочтение!