Why is 'this' in jquery chaining callbacks a DOM element?
Asked Answered
G

2

6

So I know that when using $.fn.each, $.fn.bind, etc, it is standard for the this keyword within jQuery chaining callbacks to be a DOM element.

I know in my development at least I usually want the DOM element wrapped in a jQuery set - 90% of the time I end up doing var $this = $(this). I am sure there was a good (likely performance-based) rationale for why they chose to bind to the unwrapped element but does anyone know what exactly it was?

This is one of those things that I feel like knowing the answer to might open the door for understanding the library and language at a deeper level.

Gratification answered 9/1, 2012 at 0:15 Comment(1)
The only one who could give you the real answer is Jhon Resig or another of the main developers of jQuery; personally i think that is just readibility, if you write "this.omnibox" you are not sure if its a jQuery object, but "$(this).omnibox" is pretty clear. Plus is really convinient for avoiding the creation of unnecessary jQuery objects, like when you do $(".box").not(this).remove()Zarla
H
2

Barring someone being able to point to an article by John Resig specifically addressing the question, I doubt a definitive answer is on offer. But I frequently wondered this when I started using jQuery, and have come to the conclusion that it's the least harmful thing. After all, it's entirely possible that all you need is the DOM element. If you need/want to use a jQuery wrapper around it, then $() is but three keystrokes away (or more of you do the var $this = $(this); thing). As opposed to having the library always do it for you, which involves multiple function calls and memory allocations, when it may well be that you don't need it.

For instance, consider:

$("input").each(function() {
    // Use this.value
});

There, there's no reason whatsoever for a jQuery wrapper around the DOM element. this.value is all you need for all input fields (other than input type="file", but val() won't help you there, either). In event handlers (where this is also "just" the raw element), you may not look at this at all.

But in this case:

$(":input").each(function() {
    var val = $(this).val();
    // Use `val`
});

...there's a genuine reason for using $(this): The :input selector matches several different element types (input, select, button, textarea) for which the value comes from different properties, and val() abstracts that for you.

So I've concluded that providing the raw element is a performance thing. If you don't use it at all, or you only use the basic DOM properties of it, there's no need to wrap it in a jQuery instance. If you need/want to do that, you can do it in your code.

Halette answered 9/1, 2012 at 0:25 Comment(10)
I misunderstood the question but this is exactly it.. you dont always need a jQuery object.Shaniceshanie
I'm sure that one of the core team has addressed this at some point...right?Gratification
@JaredFarrish: You've lost me. Must be my aged brain cells. ;-)Halette
The first are not DOM elements. Is that not a good example? I'm not sure I follow the premise of the question.Reversible
@JaredFarrish: The first what? The OP refers to $.fn.each, which is for looping the matched elements of a jQuery set. (As distinct from $.each, which is a more generic looping mechanism.) In my examples, the first example definitely loops through DOM elements.Halette
So if it's looping on DOM elements, why is this controversial? Is it assumed it might be a jQuery object instead? What's the point? (And I didn't, and rarely, downvote answers.)Reversible
@JaredFarrish: I didn't assume you did. :-) (I never do, it's a fool's game.) I don't think this is controversial. The OP asked why it was a raw DOM element rather than a jQuery wrapper around the element. I think I've answered that, but of course that answer (since I'm not John Resig and can't point to something he's written on the subject) is speculative/external. Perhaps that's the reason for the downvotes, although they seem harsh to me (not that I'm really bothered, although I would like to know the reasoning behind them, in case it can inform future answers I provide).Halette
I thought it had something to do with how Javascript (in the more modern version) worked, ie, .call() or .apply(). It's not magic, although digging the specifics out of the source I'm not particularly ready to do... (And I can't upvote the answer again.)Reversible
@JaredFarrish: No, it's a jQuery decision. John could have made it a jQuery wrapper around the DOM element if he'd wished, rather than using the raw DOM element. He just didn't. I've never seen an article from him saying why, but IE's JavaScript engine at the time he was writing jQuery was very slow and yet fairly dominant in the wild, and so my speculation is that he was avoiding potentially-unnecessary work.Halette
Ok, I see what you mean. I still think it's cleaner with DOM elements (being abstract from jQuery "elements"). Maybe I'm just so used to it in practice I can't see how it would/could/should be different.Reversible
S
2

I am sure there was a good (likely performance-based) rationale

I'm sure this is precisely it. If there's any likelihood that you might not need the jQuery wrapper (which there is – it's hardly uncommon to work directly on DOM properties, especially in callbacks to functions like val; indeed, you might not need to look at the element at all) then you don't want to waste time and processing resources in creating the jQuery object.

As an example, here's a jsperf that shows that doing $(this) on every element in the loop carries about as much overhead as the each function does itself.

Stuffed answered 9/1, 2012 at 0:27 Comment(3)
Fwiw, I once tested how long it takes to wrap a DOM element ($(elem)), and my results were less than a microsecond.Buzzer
@ŠimeVidas: With what JS engine? It's obviously going to be relevant. I suspect it matters less now than it did when John first wrote jQuery (for instance, lonesomeday's jsperf runs less than half as many loops on IE6 when we wrap as when we don't; IE9 does better, as does Chrome). But John was making decisions in a very different age than we now live in. That said, even then it would have had to be a lot of loops for it to really matter. :-)Halette
@T.J.Crowder jsperf.com/wrapping-with-jquery In Firefox it's a bit more than one microsecond. This is on a low-end laptop.Buzzer

© 2022 - 2024 — McMap. All rights reserved.