44

作为 jQuery 代码 ( https://coderwall.com/p/7uchvg ) 的示例,我读到表达式的$('#foo a');行为如下:

在页面中找到每个a,然后a在里面过滤#foo

而且看起来效率不高。

那是对的吗?如果是,我们应该如何以更好的方式做到这一点?

4

7 回答 7

50

这是正确的 - Sizzle(jQuery 的选择器引擎)的行为方式与 CSS 选择器相同。CSS 和 Sizzle 选择器从右到左求值,因此#foo a会找到所有a节点,然后按从#foo.

您可以通过确保您的叶子选择器具有高特异性来改进这一点,通常是通过给它们一个类或 ID。

于 2012-12-03T07:13:39.277 回答
19

我们应该如何以更好的方式做到这一点?

使用 jQuery 中的 context 参数。

$('a', '#foo');

现在 jQuery 将搜索 id: foo 元素上下文中的所有锚点。

在您的查询中,省略时默认为文档:

$('#foo a'); == $('#foo a', document); 

在这种情况下,您的查询确实效率不高。

你可以看看这篇文章

于 2012-12-03T07:14:47.673 回答
5

虽然 Sizzle 确实是一个从右到左的引擎(这与解释 css 的方式相同),但您示例中的特定选择器不会选择页面上的所有锚元素,然后将其父元素过滤为匹配“foo”的 id。Sizzle 实际上优化了任何以 ID 开头的选择器,并将其用作整个选择的上下文,而不是使用文档。换句话说,您选择的选择器基本上转换为:

document.getElementById("foo").getElementsByTagName("a")

真的,这根本不是一个糟糕的选择器。

然而,考虑到 jQuery 需要做的其他事情(包括循环元素以将它们合并到 jQuery 实例中),jQuery("#foo").find("a") 将始终是最快的,因为 jQuery 实现了一个 jQuery仅 id 选择器的对象创建快捷方式,然后它会从 #foo 进行查找。

换句话说,Sizzle 本身在做Sizzle("#foo a")and时并没有太大的不同Sizzle("a", document.getElementById("foo")),但是jQuery("#foo").find...会因为 jQuery 自己的 ID 快捷方式而更快。

顺便说一句,我对 Sizzle 的评论是假设 querySelectorAll 没有被使用。如果是,Sizzle 只是将它传递给 qsa,它仍然不如使用 jQuery 的 ID 快捷方式快。

于 2013-02-06T17:03:34.353 回答
4

您可以使用 find() 对选择器顺序进行更精细的控制:

$('#foo').find('a');

这对于更复杂的选择器当然会更令人印象深刻,您可以在其中链接 find() 和 filter()。

作为记录$('#foo').find('a') === $('a','#foo')

[更新]好的,我后来意识到这正是你的链接所说的......

jQuery 选择器引擎 (Sizzle) 已于去年进行了重构,您将在此处找到详细说明: http ://www.wordsbyf.at/2011/11/23/selectors-selectoring/

于 2012-12-03T07:33:09.327 回答
2

无需使用a内部#foo 元素进行过滤,只需将类附加到a元素并获取a具有类的元素,如$("a.class");. 这样会更有效率。

于 2012-12-03T07:13:32.437 回答
0

还有一个“自己试试”:

  1. jsperf 用于 10000 个元素上的各种选择器
  2. jsperf 用于 300 个元素上的各种选择器
  3. jsperf 用于“更具代表性的 DOM”上的各种选择器

与“平面” DOM(1 和 2)似乎没有太大区别,但嵌套 DOM 的性能差异更大。

另请注意,一些测试用例没有选择正确的元素(即$('.a')vs $('.a', context)),但我将它们从原始测试中保留下来只是为了进行比较。

于 2013-03-29T14:57:04.763 回答
-4

此示例将检索a名为foo, 的元素中的所有锚点元素,以查找页面中的每个 a ,然后根据您的需要过滤 #foo 中的 a 您应该选择a #foo

$("a #foo");

这将检索foo元素内的所有a元素。

于 2012-12-03T07:21:04.753 回答