43

In the following example the stored jQuery selector returns the wrong value. There is a possibility to store the selectors and not the result?

The js code:

// storing the jQuery selectors
var
  $container = $( '.container' ),
  $element1  = $container.find( '.element' ),
  $element2  = $( '.element', $container ),
  $element3  = $( '.element' );

// append elements to the container
for( i=0; i<10; ++i ){
  $container.append( $(element_html) );  
}

// try the stored selectors -> returns 0
console.log( "1: " + $element1.length );
console.log( "2: " + $element2.length );
console.log( "3: " + $element3.length );

Why, if I use the container selectors to find the elements, it works? It is beacuse the selector returns the pointer to the matched elements and not the elements?

// this works
console.log( "1: " + $container.find( '.element' ).length );
console.log( "2: " + $( '.element', $container )  .length );
console.log( "3: " + $( '.element' )              .length );

jsFiddle demonstration

TheGr8_Nik
  • 3,080
  • 4
  • 18
  • 33
  • jquery selectors return a query object on which you can do further operations, which is called chaining... – T J Jun 05 '14 at 07:15

2 Answers2

132

You have a fundamental misunderstanding of what

variableName = $("selector here");

does. It does not "store the selector." It runs the selector you give against the current elements in the DOM, creates a jQuery object, puts the matching elements in the jQuery object, and gives you a reference to that jQuery object. The selector is not stored (modulo jQuery internals).

So given:

<body>
<div class="foo">x</div>
</body>

Then:

var $divs = $("div.foo");
console.log($divs.length);        // 1

Gives us this:

$divs jQuery object pointing at one div in the DOM

If we then add another matching div:

$('<div class="foo"></div>').appendTo(document.body);

Our $divs still only points to the first one; adding another matching element to the DOM had no effect on the jQuery object referenced from $divs.

$divs jQuery object pointing to one div, but there are two in the DOM

If we re-run the query at that point:

$divs = $("div.foo");

...then we have:

$divs jQuery object pointing at both divs in the DOM

If you have a jQuery object containing a DOM element, and you add descendant elements to that DOM element, then using that jQuery object with (say) .find will see the descendants. That's because the parent DOM element is already there in the jQuery object. E.g., adding a span to one of the divs that we already reference from our jQuery object:

$divs jQuery object pointing at both divs in the DOM, one has a span now

If we were to use .find on $divs at that point looking for a span, we'd find it, because it's a descendant of one of the elements we already had a reference to.

If you want to re-run the DOM search again later to look for matching elements, you just use $() again; this is implicit in the above, but for clarity:

var $divs = $("div.foo");
console.log($divs.length);        // 1
$('<div class="foo"></div>').appendTo(document.body);
console.log($divs.length);        // Still 1
$divs = $("div.foo");
console.log($divs.length);        // Now it's 2

So "storing a selector," when needed, is a matter of storing the selector string somewhere, not the jQuery object.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 10
    So in answer to his question, storing the selector should be done by storing the `string` as opposed to the returned jQuery object. (Just wanted to add that, sorry if it's trivial :)) – Flater Jun 05 '14 at 07:18
  • Can I see the return of a jQuery selector like an `array of pointers` to the DOM elements? – TheGr8_Nik Jun 05 '14 at 07:31
  • 1
    @TheGr8_Nik: Yes, exactly. I've added some pictures to the answer to make that a bit clearer. jQuery objects are "sets" (as in set theory) of elements that matched the selector as of when you created the object. – T.J. Crowder Jun 05 '14 at 07:44
  • what if i have a unique elements that i'm using frequently , should i store them in variables so jquery won't search in the dom every time to find them again ? – Robert Dec 03 '15 at 09:50
  • 1
    @robert: How long is a piece of string? It totally depends. – T.J. Crowder Dec 03 '15 at 09:57
6

I think the accepted answer is excellent, but it could be interpreted to suggest that assigning JQuery objects to variables is always unsafe. Doing so is fine -- as long as the DOM object the variable references is not altered before you access it in a way that affects later code.

HTML

<div id="banner-message">
    <p>Hello World</p>
    <button>Change view</button>
</div>

JavaScript

// find elements
var banner = $("#banner-message")
var button = $("button")

// handle click and add class
button.on("click", function(){
  banner.addClass("alt");
  banner.hide().html("New HTML").fadeIn(2000);
})

JsFiddle

Bob Ray
  • 1,105
  • 10
  • 20