为啥诸如 :not() 和 :has() 之类的函数伪函数允许引用参数?
Posted
技术标签:
【中文标题】为啥诸如 :not() 和 :has() 之类的函数伪函数允许引用参数?【英文标题】:Why do functional pseudos such as :not() and :has() allow quoted arguments?为什么诸如 :not() 和 :has() 之类的函数伪函数允许引用参数? 【发布时间】:2012-09-10 15:12:22 【问题描述】:显然,正如我在评论 another answer 时发现的那样,jQuery(而不是它的底层选择器引擎 Sizzle)允许您将参数引用到 :not()
选择器和 :has()
选择器。 To wit:
$('div:not("span")')
$('span:has("span")')
在Selectors standard 中,引号始终代表字符串,而不是选择器或关键字,因此引用:not()
的参数始终无效。 This will not change in Selectors 4.
您还可以通过添加unsupported CSS selector 如:nth-last-child(1)
causing the selector to fail completely 来查看它的非标准语法:
$('div:not("span"):nth-last-child(1)')
$('span:has("span"):nth-last-child(1)')
是否有任何充分的理由(技术或其他方面)允许在此处引用?唯一想到的可能性是:
与:contains()
一致,允许引用和未引用的参数,如the old Selectors spec 所示。除了:contains()
接受字符串/关键字,而不是选择器...
与使用 $.expr[':']
的自定义伪代码的实现保持一致,它始终允许带引号和不带引号的参数。
一致且易于移植到他们的方法对应 .not()
和 .has()
(只需删除或拆分外部引号并将冒号更改为句点?)。
但我找不到任何来源支持或反对他们。事实上,引用选择器参数本身的能力也没有记录在任何地方,引用和不引用参数之间似乎也没有任何区别:
$('div:not(span)')
$('span:has(span)')
【问题讨论】:
这很可能是 Sizzle 的怪癖,而不是 jQuery 本身。 @BoltClock 对不起,我的例子很糟糕,我认为引号的唯一目的是转义。 不是一个答案,但 jQuery 表示他们自己借鉴 CSS 选择器规范,而不是忠实地实现它。也许 John Resig 会停下来回答。 @Explosion Pills:是的。在这种情况下,他们真的应该将主页上的“CSS3 Compliant”更改为“CSS3 Compatible”或类似的东西;) 看看测试套件,我想说这不是应该工作的(不是引用:not
或:has
的单个测试)github.com/jquery/sizzle/blob/master/test/unit/selector.js
【参考方案1】:
这并不特定于 :not(...)
和 :has(...)
选择器 - 实际上,所有伪
在 Sizzle 中允许引用参数。伪参数的模式
定义为:
pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:" + attributes + ")|[^:]|\\\\.)*|.*))\\)|)"
可以在91
of sizzle.js
as of 831c9c48...
线上找到
让我们添加一些缩进,使其更具可读性。 不幸的是,这仍然是一个正则表达式,所以“更具可读性”仍然 还有很多不足之处:
pseudos = (
":(" + characterEncoding + ")" +
"(?:" +
"\\(" + // literal open-paren
"(?:" +
"(['\"])" + // literal open-quote
"((?:\\\\.|[^\\\\])*?)" + // handle backslash escaping
"\\2" + // close-quote
"|" + // - OR -
"(" +
"[^()[\\]]*" +
"|" +
"(?:" +
"(?:" + attributes + ")" +
"|" +
"[^:]" +
"|" +
"\\\\." +
")*" +
"|" +
".*" +
")" +
")" +
"\\)" + // literal close-paren
"|" + // ie, 'or nothing'
")"
);
主要的收获是:单引号或双引号都可以
在伪属性中围绕参数使用。反斜杠转义是
正确处理,因此任何任意字符串都可以作为
争论。请注意,“字符串”部分以相同的匹配索引结束
作为上述正则表达式中的“选择器”部分;所以,简而言之,这就是为什么
他们被平等对待:因为pseudos
模式没有
区分两者。 edit: 从 jQuery 1.8.2 开始,参数
带引号和不带引号更明确地等效。我似乎无法
在 jQuery git 存储库中找到此代码 [帮助将不胜感激],但 the version of
1.8.2 hosted by google, having the sha1sum of a0f48b6ad5322b35383ffcb6e2fa779b8a5fcffc,有
"PSEUDO":
在线 4206
上的函数,它确实明确检测到
“引用”和“未引用”参数之间的区别,并确保它们
两者都在同一个地方结束。这个逻辑不区分
在参数的伪类型(“位置”与否)之间
为。
由于 Sizzle 使用 javascript 字符串来启动选择过程, 参数时“字符串”和“选择器”之间没有区别 被传递给函数。做出这种区分将是 可能,但据我所知,真正想要的总是 很容易从最基本的上下文中确定(即:什么类型的 正在使用伪),因此没有真正的理由使 区别。 (如有歧义,请在 cmets 中更正 我不知道的情况-我想知道!)。
那么,如果字符串和选择器之间缺乏区别是
仅仅是实现细节,为什么要显式地使用诸如:eq(...)
之类的伪指令
拒绝这样的选择?
答案很简单:它没有,真的。至少,不像 jQuery 1.8.1。 [edit: 从 jQuery 1.8.2 开始,它根本没有。的论点 “位置”伪类可以像其他任何东西一样被引用。下面 关于 1.8.1 的实现细节的注释留作 历史好奇心]
:eq(...)
等函数实现为:
"eq": function( elements, argument, not )
var elem = elements.splice( +argument, 1 );
return not ? elements : elem;
:eq(...)
收到参数的时候,还在
单论的形式(引号和所有)。不像:not(...)
,这个
论点没有经过compile(...)
阶段。的“拒绝”
无效的参数实际上是由于快捷方式转换通过
+argument
,对于任何带引号的字符串(在
转,从不匹配任何东西)。这是另一个实现
细节,尽管在这种情况下,一个“正确”的行为 (同样,到目前为止
据我所知。是否存在这样的非数字参数
函数实际上应该匹配?)
编辑: 从 jQuery 1.8.2 开始,事物已经进行了一些重构,并且
“位置”伪类不再接收“原始”参数。因此,
:eq(...)
等现在接受引用的参数。这种变化
似乎是另一个错误修复的副作用,因为在 af8206ff.. 的更改日志中没有提到对引用参数的支持,这是为了修复 an error in handling :first
and :last
, jQuery bug #12303。这个提交是使用git bisect
和a relatively simple phantomjs script 找到的。值得注意的是,在e89d06c4.. 中的 Sizzle 重写之后,Sizzle 不仅会在 :eq("3")
等选择器上静默失败,它实际上还会抛出异常。这应该被视为更多证据表明:eq("3")
支持不是预期行为。
确实有关于自定义过滤器的基本原理,其论点 在某些情况下可以被认为是字符串,有时是 选择器,无论它们表面上看起来像什么,取决于 评估它们的方法......但即将到来 迂腐的。应该说没有区别就足够了 至少在调用函数时让事情变得更简单,没有 无论它们可能代表什么,都期望一个字符串表示。
简而言之,整个情况可以认为是一个实现 细节,并且植根于选择器作为 首先是字符串(否则您如何将它们放入 Sizzle 中?)。
【讨论】:
你没听说过raw strings吗?或者也许只有我和 Python…… +1 花时间格式化正则表达式并尝试解释它(这是一项艰巨的任务)。赏金由你来拿。 我想我真的需要重新经历一遍。你的评论促使我再看一眼,我想我可能读错了,尽管我做了所有的格式化工作。自从 jQuery 1.8.2 发布以来,我还没有真正经历过标记化过程,所以我真的应该确保推理仍然准确。 @YatharthROCK:我不确定提到原始字符串是指什么。你能扩展你的意思吗?如果您的意思是我应该在上面使用"\\("
等的替代方法:目的是完全模仿原始正则表达式字符串的内容。我对它所做的唯一更改是拆分和重新缩进组件(这样应该很容易找到原始字符串中的对应点)。否则,我可能会使用 PCRE /x 语法来简单地显示等效的正则表达式,而不是“相同的”。
原始字符串是完全按照输入的方式解释的字符串——无需再次转义字符。它们在处理正则表达式时会派上用场。通过[我的评论](***.com/questions/12475595/…,我的意思是如果你使用原始字符串,你就不必转义所有的反斜杠。它看起来会好很多。以上是关于为啥诸如 :not() 和 :has() 之类的函数伪函数允许引用参数?的主要内容,如果未能解决你的问题,请参考以下文章
为啥jQuery或诸如getElementById之类的DOM方法找不到元素?
为啥jQuery或诸如getElementById之类的DOM方法找不到元素?
为啥jQuery或诸如getElementById之类的DOM方法找不到元素?
为啥jQuery或诸如getElementById之类的DOM方法找不到元素?