What is the different in performance and the handling of these two different jQuery statements:
Number One:
$('#selector1, #selector2, .class1').on('click', function () { //stuff });
Number Two:
$(document).on('click', '#selector1, #selector2, .class1', function () { //stuff });
I know that one does delegation and the other doesn't.
But what does that mean?
Don't both do some sort of action when you click on '#selector1, #selector2, .class1'
?
In the end, isn't it the same?
The first one binds 3+ event handlers (one to each element ) that are lost once the elements are replaced. The first one will fail if the elements don't exist yet.
The second one binds 1 event handler (one to
document
) that will never be lost unless you explicitly remove it. And once the handler is called here, the event has already propagated todocument
. Any time you click anywhere on the page, jQuery internally checks if it was on any element that matches the selector you gave and fires the handler you gave if it does. This is only if the event propagated todocument
and wasn't stopped at lower level element.The second one can be bound even before document ready, and it will still work even if the elements don't exist yet.
Number One will hook the
click
event on the elements that exist when you execute that statement. E.g., the handler is directly hooked to the actual elements that match when you execute that call.Number Two will hook the
click
event on the document, and on receipt of any clicks, will check to see if the element that was actually clicked matches any of the given selectors, and if so will fire the handler. This is event delegation rather than a direct hookup.So that means several things:
click
work with Number Two (because it relies on the event bubbling up the DOM to the document level).There are times when using a directly-hooked handler is better, and times when event delegation (usually using something more focussed than the
document
, though) is better. Usually, the dividing line between those is a judgement call, but for example if you want to respond to clicks on table rows, you're probably better off hooking theclick
event on thetable
element with atr
selector, rather than attaching theclick
event of every single table row, particularly if you update the table dynamically. Whereas if you have a unique button you know exists in the DOM when you're hooking up your handler, and you want to fire a specific function when that button (but not anything else) is clicked, a direct handler probably makes more sense.Here's an example (live copy):
HTML:
JavaScript:
Note that when you click the "click me" paragraph, you get two new paragraphs added to the document, one of them the result of the first
on
call, the other the result of the second. But note that if you click either of those two new paragraphs, you only see the handler from the secondon
call (the delegated one), not the first. That's because those paragraphs didn't exist when you hooked up the first handler.The
on()
method attaches a event handler for each of the elements matched by the jQuery object. If you pass the optional selector to theon()
method, the handler will only fire if the event occurred on a descendant of that element.Due to this, the first example will attach multiple event handlers, as the jQuery object contains 3 elements. However, the second example will attach a single event handler, which will handle the click event for all
'#selector1, #selector2, .class1'
'sObviously this leaves the first at a performance disadvantage if many elements are matched (as multiple event handlers are bound, compared to the single one attached in the second example).
For a small number of objects, choosing the second example over the first is a micr-optimization at best. However if you've got lots of elements (list items, rows in a table), you should seriously consider using the second example over the first.
Because
on()
attaches handlers to each of the elements matched by the jQuery object, you cannot attach handlers directly to elements that are not yet in the DOM (e.g. if you wish to add the elements programatically via code or through AJAX). This is where the ability to provide a selector as a parameter toon()
becomes extremely useful; this allows you to attach an event handler to an element that is currently in the DOM, but which will handle events that fire on elements that are not yet in the DOM (but which match the selector you provided).Put another way, in the first example, jQuery attaches an event handler to all elements that match the
#selector1, #selector2, .class1
selector; and so will miss all elements that haven't been registered in the DOM yet.On the other hand, if you use the second example, jQuery attaches an event handler to all elements that match the
document
selector (e.g. the singleDocument
element), and attaches a handler to it which will fire if the event it receives originated from a element matched by the selector#selector1, #selector2, .class1
; this has the advantage of working for all future#selector1, #selector2, .class1
elements.You can see this in operation here; http://jsfiddle.net/kntR7/
Because number two is bound to the
document
, any element which accepts the handler for the same event will receive the handler before (asdocument
is the last place which receives the handler through event propagation), so if it chooses to cancel the event usingevent.stopPropagation()
orevent.stopImmediatePropagation()
, the handler will never be reached.You can see this in operation here; http://jsfiddle.net/mkNyU/
For anyone familiar with the pre 1.7 syntax, here's how
on
can be used:So your first line (
$('#selector1, #selector2, .class1').on('click', function)
) is abind
format to attach events to existing elements.Your second line (
$(document).on('click', '#selector1, #selector2, .class1', function)
) is alive
format to attach events to any element that matches the selector when the event occurs, whether or not the elements exist within the dom at the time of binding.