作为 jQuery 代码 ( https://coderwall.com/p/7uchvg ) 的示例,我读到表达式的$('#foo a');
行为如下:
在页面中找到每个
a
,然后a
在里面过滤#foo
。
而且看起来效率不高。
那是对的吗?如果是,我们应该如何以更好的方式做到这一点?
作为 jQuery 代码 ( https://coderwall.com/p/7uchvg ) 的示例,我读到表达式的$('#foo a');
行为如下:
在页面中找到每个
a
,然后a
在里面过滤#foo
。
而且看起来效率不高。
那是对的吗?如果是,我们应该如何以更好的方式做到这一点?
这是正确的 - Sizzle(jQuery 的选择器引擎)的行为方式与 CSS 选择器相同。CSS 和 Sizzle 选择器从右到左求值,因此#foo a
会找到所有a
节点,然后按从#foo
.
您可以通过确保您的叶子选择器具有高特异性来改进这一点,通常是通过给它们一个类或 ID。
我们应该如何以更好的方式做到这一点?
使用 jQuery 中的 context 参数。
$('a', '#foo');
现在 jQuery 将搜索 id: foo 元素上下文中的所有锚点。
在您的查询中,省略时默认为文档:
$('#foo a'); == $('#foo a', document);
在这种情况下,您的查询确实效率不高。
你可以看看这篇文章。
虽然 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 快捷方式快。
您可以使用 find() 对选择器顺序进行更精细的控制:
$('#foo').find('a');
这对于更复杂的选择器当然会更令人印象深刻,您可以在其中链接 find() 和 filter()。
作为记录$('#foo').find('a') === $('a','#foo')
[更新]好的,我后来意识到这正是你的链接所说的......
jQuery 选择器引擎 (Sizzle) 已于去年进行了重构,您将在此处找到详细说明: http ://www.wordsbyf.at/2011/11/23/selectors-selectoring/
无需使用a
内部#foo
元素进行过滤,只需将类附加到a
元素并获取a
具有类的元素,如$("a.class");
. 这样会更有效率。
还有一个“自己试试”:
与“平面” DOM(1 和 2)似乎没有太大区别,但嵌套 DOM 的性能差异更大。
另请注意,一些测试用例没有选择正确的元素(即$('.a')
vs $('.a', context)
),但我将它们从原始测试中保留下来只是为了进行比较。
此示例将检索a
名为foo
, 的元素中的所有锚点元素,以查找页面中的每个 a ,然后根据您的需要过滤 #foo 中的 a 您应该选择a #foo
$("a #foo");
这将检索foo
元素内的所有a
元素。