1

In jQuery

$('html head').length                             // 1

And

$('html').find('head').length                     // 1

And

$('html').find('head').filter('html head').length // 1

BUT

$('html').find('html head').length                // 0

Why?

Barney
  • 16,181
  • 5
  • 62
  • 76
  • 2
    Just leaving this one here: `$('html').andSelf().find('html head').length` – epascarello Jun 05 '13 at 13:53
  • @epascarello thanks! I would've accepted that as an answer, TBH — it was by trying `$('body').andSelf().find('html p').length === 0` that I realised jQuery essentially ignores everything above the current scope for the purposes of `find`. – Barney Jun 05 '13 at 14:13
  • I really don't understand meaning of this. Why not just use: $(document).find('html head').length then? – A. Wolff Jun 05 '13 at 14:16
  • Maybe I'm being dense, but what would be the purpose of `find()` if it didn't search within context? – Evan Davis Jun 05 '13 at 14:42
  • @Mathletics it absolutely should! I wouldn't expect `$('html').find('html body')` to retrieve anything, for instance. But the element described by `html head` is always within the context of `html`. – Barney Jun 05 '13 at 14:50
  • Now I'm doubly confused; what is special about `$('html').find('html head')` vs `$('html').find('html body')`? – Evan Davis Jun 05 '13 at 14:57
  • @Mathletics sorry, I'm getting muddled. `html head` was too simple an example. I would expect `$('body').find('html.lt-ie9 div')` to work (*if* the html did indeed have that class), for example. But this question isn't about use case, it's about jQuery's internal mechanisms. – Barney Jun 05 '13 at 15:07
  • Based on your logic, `$('li').find('div a')` would return anchors that were direct children of `li`, provided the `li` was nested in a `div` (in addition to the standard matched set of anchors within divs within list items.) – Evan Davis Jun 05 '13 at 16:22
  • Here, I made a fiddle to show how wacky this is: http://jsfiddle.net/PdxSb/1/ – Evan Davis Jun 05 '13 at 16:29
  • @Mathletics yes, that's what I'm talking about. It was tough, but I got there in the end ;) – Barney Jun 05 '13 at 16:55

3 Answers3

7

Because there is no <html> tag nested inside <html> tag

But:

$('html').find('html, head').length // return 1 here coz comma means 'or'
A. Wolff
  • 74,033
  • 9
  • 94
  • 155
  • I'm not looking for the `html` tag, I'm looking for a `head` tag that is a descendant of an `html` tag (ie `html head`) inside the `html` tag. Essentially, I want the same thing as what the first 3 expressions return. – Barney Jun 05 '13 at 13:58
  • So just: $('html').find('head') Why not use it? – A. Wolff Jun 05 '13 at 14:01
  • How come selectors in $.fn.find() cannot reference the tree beyond the current $ scope? – Barney Jun 05 '13 at 14:02
  • `html head` *is* a descendant of `head` though. Using `html` && `head` was a bad example in hindsight — too simple. There is no purpose to it here — the question is in the title: I wasn't honestly trying to find the `html` tag for Christ's sake (well done on the upvotes though!). – Barney Jun 05 '13 at 14:15
5

Per the documentation:

Find: Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element.

HTML is not a descendant of HTML

http://api.jquery.com/find/

tymeJV
  • 103,943
  • 14
  • 161
  • 157
1

Your first selector $('html head') works just like find - gets any <head> descendants of HTML

HTML──┐  start here and find head
    HEAD

Your second selector $('html').find('head') gets html element - then finds all descendant <head> elements

HTML──┐ start here and find head
    HEAD

Your third selector $('html').find('head').filter('html head') gets html element - then finds all descendant <head> elements - the filter is really pointless because the returned head elements are guaranteed to be descendants of html because of this $('html').find('head')

HTML──┐  start here and find head
    HEAD

Your lastone that isn't working $('html').find('html head') is searching for structure below

HTML──┐  start here and find "html head" 
    HTML──┐    
         HEAD
but really your structure is like this
HTML──┐  
    HEAD

which html doesn't have a descendant html element so that results in 0 elements returned

If you want to keep the HTML element in the collection you can use .addBack()

$('html') // get html element
  .find('html head') // find head element
  .addBack() // add back the html element
  // if jQuery 1.7 and lower use .andSelf()
  .length  // this will result in 1 element - the HTML element
wirey00
  • 33,517
  • 7
  • 54
  • 65