When used with the child selector >, the two variants of jQuery’s “has” behave differently.
Take this HTML:
<div>
<span>Text</span>
</div>
Now:
$("div:has(>span)");
would return it, while:
$("div").has(">span");
would not. Is it a bug or a feature? Compare here: http://jsfiddle.net/aC9dP/
EDIT: This may be a bug or at least undocumented inconsistent behavior.
Anyway, I think it would be beneficial to have the child selector consistently work as an unary operator. It enables you to do something that otherwise would require a custom filter function — it lets you directly select elements that have certain children:
$("ul:has(>li.active)").show(); // works
$("ul").has(">li.active)").show(); // doesn't work, but IMHO it should
as opposed to:
$("ul").filter(function () {
return $(this).children("li.active").length > 0;
}).show();
I’ve opened a jQuery ticket (7205) for this.
This happens because the sizzle selector is looking at all Div’s that have span children in the :has example. But in the .has example, it’s passing all DIV’s to the .has(), which then looks for something that shouldn’t be a stand-alone selection. (“Has children of nothing”).
Basically, :has() is part of the selection, but .has() gets passed those divs and then re-selects from them.
Ideally, you don’t use selectors like this. The > being in the selector is probably a bug, as it’s semantically awkward. Note: the child operator isn’t meant to be stand-alone.
Sizzle vs target.sizzle:
I’m always talking about v1.4.2 of jquery development release.
.has (line 3748 of jQuery)
Description: Reduce the set of matched elements to those that have a descendant that matches the selector or DOM element.
Code:
Line 3642 relates to a 2008 plugin compareDocumentPosition, but the important bit here is that we’re now basically just running two jquery queries here, where the first one selects
$("DIV")and the next one selects$(">span")(which returns null), then we check for children.:has (line 3129 of jQuery)
Description: Selects elements which contain at least one element that matches the specified selector.
Code:
return !!Sizzle( match[3], elem ).length;They are two differnt tools, the :has uses sizzle 100%, and .has uses targets passed to it.
Note: if you think this is a bug, go fill out the bug ticket.