5 ms·
if you need to do stuff with a inside of the function, then you have to do $(this), so every time an a in that collection is clicked $() is run. In my first ex
by emehrkay 16y ago
if you need to do stuff with a inside of the function, then you have to do $(this), so every time an a in that collection is clicked $() is run.
In my first example I actually took that problem out of the equation by looping through the collection and storing the jQuery'd a as a var accessible via the event closure. However, if you want to reference an element in that collection later in your code, you have to jump though the jQuery selection hoops.
But you are right, sometimes you may not need to have every element in your selection wrapped in the jQuery object and it is up to you to determine which solution to use in a given case. But I do feel that most cases I see devs constantly wrapping $(this) inside of event handlers when they could have made an external reference/collection before hand and used that.
$('a').hover(
function(e){
$(this).doSomething();
},
function(e){
$(this).doSomething();
}
);
vs
var as = $('a'),
collected //using the same method as above;
as.each(function(i, e){
collected[i].hover(
function(e){
collected[i].doSomething();
},
function(e){
collected[i].doSomething();
}
);
);
This is a very rudimentary example and I know that there is a simpler way to accomplish this, but imagine code with multiple collected items who all match up on a 1 to 1 basis collecting the pre-wrapped objects has its advantages.
- xtian 16y agoBut wouldn't multiple potentially long loops on initial load have a greater possible impact on user experience than one extra call to $() per event?
- emehrkay 16y agoGreat point. I think that my simplistic example is just that, simplistic. A better solution for huge collections would be to memoize the retrieval of the $() obj with something like var memd = {}, getMem = function(obj){ var o; if(memd[obj]){ o = memd[obj]; }else{ o = memd[obj] = $(obj); } return o; }; and call that function instead of calling $() while inside of an event handler (I havent tested this code, but the concept is straight forward)
- arethuza 16y agoI don't want to appear snarky, but as you admit yourself ("I dont have any data on it") you don't know if creating a jQuery object is expensive or not (to be fair, I don't know either) - so why all the extra complexity if you don't know whether the thing you are trying to avoid (creating instance of jQuery during event handlers) actually causes problems or not?
- emehrkay 16y agoWell given that a lot of the "pro" jQuery tips say that one should avoid rerunning the selector in favor of some sort of memoization: $('.class').doSomehting(); $('.class').doSomethingElse(); $('.class').thirdThing(); in favor of var ele = $('.class'); ele.doSomething(); ele.doSomethingElse(); ele.thirdThing(); I would only assume that re-querying with the jQuery object inside of event handlers has the same adverse effects. Lets say you have a very simple tabbed thing //this is code that i've seen around var tabs = $('a.tab'), containers = $('div.container'); tabs.click(function(e){ var index = tabs.indexOf($(this)); tabs.removeClass('active'); $(this).addClass('active'); containers.css('display', 'none'); $(containers[index]).css('display', 'block'); }); vs //this is how id handle a simple tabber var tabs = $('a.tab'), containers = $('div.container'), all_containers = $.map(containers, function(i, c){ return $(c); }); $.each(all_tabs, function(i, tab){ var t = $(tab); t.bind('click', function(e){ tabs.removeClass('active'); t.addClass('active'); containers.css('display', 'none'); all_containers[i].css('display', 'block'); }); }); I just feel that the first one, while more concise (has it obvious areas of improvement, but general idea) would wind up being more expensive than the second. If running the jQuery object isnt too expensive, why is the practice of rerunning the same selector frowned upon?
- xtian 16y agoInteracting with the DOM is what's slow. It's especially slow if the native querySelectorAll method isn't available because any non-trivial selections necessitate iterating over the DOM tree. That's why you don't want to re-query a selection multiple times. That's also why it's recommended that all selections start with an id. The size of the tree to iterate over can be quickly reduced using the native getElementByID method. In the case of $(this), the DOM node is already passed to the event handler, so wrapping it in a jQuery object doesn't touch the DOM tree at all. Furthermore, I always cache it (var $this = $(this);) if I'm going to use it more than once. Also, in your first example, you don't have to rewrap containers[index] in a jQuery object. All the elements in the selection are already wrapped.