Reputation: 20747
I have this html:
<div>hi</div>
<div>bye</div>
And I run this with jQuery 1.12.3 (I doubt the version matters but it's here for reference):
$(document).ready(function(){
var $divs = $('div');
alert($divs.length); // Expect 2, get 2
$('div:first').remove();
alert($divs.length); // Expect 2, get 2
// Why does expectation not match reality?
// Is this not triggering a DOM search?
alert($($divs).length); // Expect 1, get 2
$divs = $('div');
alert($divs.length); // Expect 1, get 1
});
Note: if you've made it this far then please notice that my question is in the comments of the jQuery code.
I'm sure this is fairly simple but I would like to know in lay-mans terms and hopefully get some direct documentation links since everything on Google guides me to endless blog posts which seem to have copy+pasted one another.
Additionally, why does this work?
html
<div>
<p>1</p>
<p>2</p>
<p>3</p>
<p>4</p>
<p>5</p>
</div>
jQuery
$(document).ready(function(){
var $div = $('div');
alert($div.find('p').length); // expect 5, get 5
$div.find('p:first').remove();
alert($div.find('p').length); // expect 5, get 4
});
Shouldn't $div
still contain 5 <p>
s?
Does .find()
trigger a DOM re-query on $div
?
Upvotes: 0
Views: 65
Reputation: 115282
The $('div:first').remove();
will remove the element from the dom, but $('div')
is not a live collection so which will not get updated. Also you are re-wrapping the existing jQuery object which doesn't have any effect at all, you can check it on the jQuery library code.
Lear more about jQuery object here : The jQuery Object
As per the docs :
Given a jQuery object that represents a set of DOM elements, the .find() method allows us to search through the descendants of these elements in the DOM tree and construct a new jQuery object from the matching elements
find()
will iterate over the elements and then by using the descendants it will generate the new jQuery object.
The find function is working as follows ( following code taken from jQuery library )
function( selector ) {
var i,
len = this.length,
ret = [],
self = this;
if ( typeof selector !== "string" ) {
return this.pushStack( jQuery( selector ).filter( function() {
for ( i = 0; i < len; i++ ) {
if ( jQuery.contains( self[ i ], this ) ) {
return true;
}
}
} ) );
}
for ( i = 0; i < len; i++ ) {
jQuery.find( selector, self[ i ], ret );
}
// Needed because $( selector, context ) becomes $( context ).find( selector )
ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
ret.selector = this.selector ? this.selector + " " + selector : selector;
return ret;
},
Which initially selects elements from dom using selector string provided inside find method after it's filtering based on parent, so the removed element will not get selected. So find()
only result the elements which is present in the dom.
Upvotes: 2
Reputation: 3062
On the line
alert($($divs).length); // Expect 1, get 2
You are still referring to the original variable which has a length of two. You are re-wrapping it as a jquery object, but that won't change it.
To reflect the DOM changes, you have to select again. Which you do before the last attempt, and there the count is correct.
This is not 'caching' behaviour, but variable behaviour.
UPDATE:
As for the second question - the find()
does indeed do a DOM query as per the doc comment that Pranav C Balan included in his answer.
Upvotes: 3