Alexander Solonik
Alexander Solonik

Reputation: 10230

jQuery methods Vs jQuery selectors

I was recently assigned a very small but complex task in jQuery, the requirement was quite simple, given the following HTML :

<div> 
   <span id="myid2151511" class="myclass23462362">....foobar....</span>
   <span id="myid2151512" class="myclass23462362">....YoLO....</span>
   <span id="myid2151513" class="myclass23462362">....lalal....</span>
   <span id="myid2151514" class="myclass23462362">....foobar....</span>
</div>

What i have to do i recursively go through all the span under div, With a certain id and check if the values contained in the spans is foobar, So i can up with the following jQuery code:

$(function(){
     $('div [id^="myid"]:contains("foobar"):last').css({'background' : 'rgb(227, 216, 22)' })
});

FIDDLE HERE

Its quite a complex bit of code by itself, but the jQuery documentation made it a cakewalk for me as for as understanding the code is concerned.

By now i am comfortable writing code like so in jQuery:

$('some-Element').somemethod().anothermethod().yetanothermethod();

Every function returns a value in the above jQuery statement, so chain ability becomes a reality.

but when i see code like so.

$('div [id^="myid"]:contains("foobar"):last').css({'background' : 'rgb(227, 216, 22)' });

I am thrown a bit off the hook(although i managed to write the above line myself), notice how alot of the filtering is done by a selector :last and :contains, to me they appear to be working much like some kind of a jQuery method. So my question is, how do these selectors in jQuery work in comparison to jQuery methods ?

If anybody could explain or give me a vague idea, it would be Fantastic.

EDIT ::

well to clarify my question in one line, to me $(".someClass").eq('10'); makes sense, but somehow $(".someClass:eq(10)") does't , i mean it works, but how on earth is it implemented internally ?(I wrote this edit after reading the answers below, and well this question has been thoroughly answered by now, but this edit is just to clarify my question.).

Upvotes: 0

Views: 192

Answers (2)

dmeglio
dmeglio

Reputation: 2830

That's an interesting question. The short answer is they both accomplish the same thing. Of course though, there's always more to the story. In general:

$('div [id^="myid"]:contains("foobar"):last').css({'background' : 'rgb(227, 216, 22)' });

Is equivalent to:

$("div").find("[id^='myid']").filter(":contains('foobar')").last().css({'background' : 'rgb(227, 216, 22)' });

Most of the time when you call $(), jQuery is calling document.querySelectorAll(). This is a browser implemented function that grabs elements based on a selector. That complex string you create is passed to this method and the elements are returned.

Naturally, things implemented by the browser are faster than JavaScript so the less JavaScript and more C++, the better. As a result, your example passing everything as a selector is likely to be faster as it just sends it all to the browser as one call and tells it "do it." Calling $(), contains(), last() on the other hand is going to call querySelectorAll multiple times and therefore it will likely be slower since we're doing more JavaScript as opposed to letting the browser do the heavy lifting in one shot. There are exceptions though. JQuery generally calls querySelectorAll. However, there are times when it doesn't. This is because jQuery extends what querySelectorAll is capable of.

For example, if you do something like $(".someClass:eq(10)") per the jQuery documentation:

jQuery has extended the CSS3 selectors with the following selectors. Because these selectors are jQuery extension and not part of the CSS specification, queries using them cannot take advantage of the performance boost provided by the native DOM querySelectorAll() method. To achieve the best performance when using these selectors, first select some elements using a pure CSS selector, then use .filter().

So in that case, while $(".someClass:eq(10)") might seem to be faster, in reality $(".someClass").eq(10) or $(".someClass").filter(":eq(10)") is going to be faster since the first call will be executed as JavaScript code. The latter two will first call querySelectorAll to select by class, then only use JavaScript to find the 10th element. When jQuery has to do the selection in pure JavaScript, it does it using the Sizzle engine which is fast, very fast, but not faster than native code in the browser. So again, the short answer is, they're the same thing, the long answer is, it depends. If you're interested in all the extensions that fall into that category, the link to the jQuery documentation I included lists them.

Upvotes: 4

user3870546
user3870546

Reputation:

First of all, yes nikhil was right. ID is unique identifier and can be only used once. If you are willing to apply same styles to several elements, or you to use it to select several elements together use class attribute. But however, i couldn't understand your question. But maybe this could help

there is function in javascript which is widely supported by almost all major browsers

document.querySelectorAll("div [id^=myId]");

in fact you could write your own library (well not as advanced one like jquery but)

var $ = function(selector){
    return document.querySelectorAll(selector);
}

// and then you could use it like this
var elementsWithMyId = $("div [id^=myId]");
// where elementsWithMyId will contain array of all divs which's id start with myId

so as i understood your question, No. there is no magic happening behind jQuery selections it's just browser built in function which is kinda shortened by jquery. of course they added tons of new features, which would work like this:

var $ = function(selector){
    var elementsArray = document.querySelectorAll(selector);

    elementsArray.makeBlue = function(){
         for(var i = 0; i < elementsArray.length; i++){
             elementsArray[i].style.backgroundColor = "blue";
         }
         // so elementsArray will now have function to make all of its
         // div blues. but if you want to have chain like that, we have to return this array not just make all of it blue
        return elementsArray;
    }

    elementsArray.makeRed = function(){
         for(var i = 0; i < elementsArray.length; i++){
             elementsArray[i].style.backgroundColor = "red";
         }
        return elementsArray;
    }

    return elementsArray;
}

// so now you can use it like this

// this returns array which has options make blue, and make red so lets use make blue first
// makeBlue then returns itself, meaning it returns array which has again options of making itself red and blue so we can use makeRed now
$("div [id^=myId]").makeBlue().makeRed();

and thats it!

Upvotes: 1

Related Questions