这不是特定于:not(...)
和:has(...)
选择器的——实际上,Sizzle 中的所有伪都允许引用参数。伪参数的模式定义为:
pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:" + attributes + ")|[^:]|\\\\.)*|.*))\\)|)"
可以在91
截至sizzle.js
的线上找到831c9c48...
让我们为其添加一些缩进,使其更具可读性。不幸的是,这仍然是一个正则表达式,因此“更具可读性”仍然有很多不足之处:
pseudos = (
":(" + characterEncoding + ")" +
"(?:" +
"\\(" + // literal open-paren
"(?:" +
"(['\"])" + // literal open-quote
"((?:\\\\.|[^\\\\])*?)" + // handle backslash escaping
"\\2" + // close-quote
"|" + // - OR -
"(" +
"[^()[\\]]*" +
"|" +
"(?:" +
"(?:" + attributes + ")" +
"|" +
"[^:]" +
"|" +
"\\\\." +
")*" +
"|" +
".*" +
")" +
")" +
"\\)" + // literal close-paren
"|" + // ie, 'or nothing'
")"
);
主要的收获是:可以在伪属性中的参数周围使用单引号或双引号。反斜杠转义得到了正确处理,因此任何任意字符串都可以作为参数传入。请注意,“字符串”部分与上述正则表达式中的“选择器”部分在相同的匹配索引中结束;所以,简而言之,这就是它们被平等对待的原因:因为pseudos
模式没有区分两者。编辑:从 jQuery 1.8.2 开始,带引号和不带引号的参数更明确地等效。我似乎无法在 jQuery git 存储库中找到此代码 [帮助将不胜感激],但由 google 托管的 1.8.2 版本具有 a0f48b6ad5322b35383ffcb6e2fa779b8a5fcffc 的 sha1sum,具有
"PSEUDO":
在线功能4206
,它确实明确地检测到“引用”和“未引用”参数之间的差异,并确保它们都在同一个地方结束。此逻辑不区分参数所针对的伪类型(“位置”与否)。
由于 Sizzle 使用 Javascript 字符串来启动选择过程,因此在将参数传递给函数时,“字符串”和“选择器”之间没有区别。进行这种区分是可能的,但据我所知,实际想要的总是很容易从最基本的上下文中确定(即:使用哪种类型的伪),所以没有真正的理由做出区分。(如果有任何我不知道的模棱两可的情况,请在评论中更正 - 我想知道!)。
那么,如果字符串和选择器之间缺乏区别仅仅是实现细节,为什么诸如:eq(...)
明确拒绝此类选择之类的伪类呢?
答案很简单:它没有,真的。至少,不是 jQuery 1.8.1。[编辑:从 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(...)
阶段。无效参数的“拒绝”实际上是由于快捷方式转换 via
+argument
,这将导致NaN
任何带引号的字符串(反过来,它永远不会匹配任何内容)。这是另一个实现细节,尽管在这种情况下是“正确”的行为(再次,据我所知。是否存在此类函数的非数字参数实际上应该匹配的情况?)
编辑:从 jQuery 1.8.2 开始,事物已经进行了一些重构,并且“位置”伪类不再接收“原始”参数。结果,引用的参数现在被接受:eq(...)
等。此更改似乎是另一个错误修复的副作用,因为在af8206ff..的更改日志中没有提及对引用参数的支持,该更改旨在修复处理中的错误,:first
以及:last
jQuery 错误 #12303。这个提交是使用一个相对简单git bisect
的phantomjs 脚本找到的。值得注意的是,在e89d06c4..中的 Sizzle 重写之后,Sizzle 不仅会因为选择器而静默失败,例如:eq("3")
,它实际上会抛出一个异常。这应该被视为:eq("3")
支持不是预期行为的更多证据。
确实有关于自定义过滤器的基本原理,其参数在某些情况下可以被认为是字符串,有时可以被认为是选择器,无论它们表面上看起来像什么,这取决于它们被评估的方法......但是很多都在接近迂腐的。可以说,在调用函数时,至少没有区别会使事情变得更简单,无论它们代表什么,都期望字符串表示。
简而言之,整个情况可以被认为是一个实现细节,其根源在于选择器首先是作为字符串传递的(否则你如何将它们放入 Sizzle 中?)。