如何评估jQuery选择器$('#foo a')?

Afs*_*ani 44 javascript performance jquery jquery-selectors sizzle

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

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

它看起来效率不高.

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

Chr*_*ald 50

这是正确的 - Sizzle(jQuery的选择器引擎)的行为与CSS选择器的行为相同.CSS和Sizzle选择器从右到左进行评估,因此#foo a将找到所有a节点,然后通过下降的节点对其进行过滤#foo.

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

  • +1我不知道如何评估选择器 (20认同)
  • Sizzle可能,但是......在Chrome上,[这个jsperf](http://jsperf.com/does-id-el-find-all-els-first)显示`$('#id span')`是10x比'$('span')更快,我认为这与所描述的算法不一致. (8认同)
  • 值得注意的是,你可以通过使用指定的JQuery函数来绕过sizzle引擎,例如`find()`或`children()`.所以代替`$("#foo a")`你可以使用`$("#foo").find("a")` (8认同)
  • 你测试案例是错误的.http://jsperf.com/does-id-el-find-all-els-first/4 (5认同)

And*_*ies 19

我们该怎样以更好的方式做到这一点?

使用jQuery中的context参数.

$('a', '#foo');
Run Code Online (Sandbox Code Playgroud)

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

在您的查询中,上下文默认为省略时记录:

$('#foo a'); == $('#foo a', document); 
Run Code Online (Sandbox Code Playgroud)

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

你可以看一下这篇文章.


小智 5

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

document.getElementById("foo").getElementsByTagName("a")
Run Code Online (Sandbox Code Playgroud)

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

但是,鉴于jQuery需要做的其他事情(包括循环遍历元素以将它们合并到jQuery实例上),jQuery("#foo").find("a")将永远是最快的,因为jQuery实现了jQuery id-only选择器的对象创建快捷方式,然后它根据#foo进行查找.

换句话说,灒本身并不做时多不同的Sizzle("#foo a")Sizzle("a", document.getElementById("foo")),但jQuery("#foo").find...会因为jQuery自己的ID快捷的速度更快.

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