Sizzle引擎分析

Sizzle引擎分析Sizzle 引擎 是啥 不懂 用过 jQuery 不 没错 JQ 的核心就是这个 话不多说 开始分析一 Sizzle 构造器在 jquery fn init 构造器函数中 通过调用 jQuery context find selector 函数来解析并匹配 DOM 元素 jQuery find 函数实际上是引用 Sizzle 函数 而 Sizzle 函数仅是 Sizzle 引擎的构造器

Sizzle引擎?是啥?

不懂?用过jQuery不?没错,JQ的核心就是这个。

话不多说,开始分析

一、Sizzle构造器

在jquery.fn.init()构造器函数中,通过调用jQuery(context).find(selector)函数来解析并匹配DOM元素。jQuery.find()函数实际上是引用Sizzle()函数,而Sizzle()函数仅是Sizzle引擎的构造器,它主要调用Sizzle.find()函数在DOM文档树中查找与CSS语法相匹配DOM的元素节点的集合。jQuery名字中Query的意义就体现在这里。

下面来分析一下Sizzle构造器函数。该函数是整个Sizzle引擎的入口。

 1 var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
2 done = 0,
3 toString = Object.prototype.toString,
4 hasDuplicate = false,
5 baseHasDuplicate = true,
6 rBackslash = /\\/g,
7 rNonWord = /\W/;
8 /**
9 * 上面这个正则比较复杂,把她拆分一下
10
11 /
12 (
13 (?:\((?:\([^()]+\) 匹配伪类选择符
14 |[^()]+)+\) 匹配函数式选择符
15 |\[(?:\[[^\[\]]*\] 匹配属性选择符
16 |['"][^'"]*['"] 匹配属性选择符
17 |[^\[\]'"]+)+\] 匹配属性选择符
18 |\\. 匹配class选择符
19 |[^ >+~,(\[\\]+)+ 匹配关系选择符
20 |[>+~] 匹配关系选择符
21 )
22 (\s*,\s*) 匹配选择符组中间的分隔符
23 ?
24 ((?:.|\r|\n)*)
25 */
26 // Sizzle选择器引擎构造函数
27 // 参数说明:
28 // selector: 选择器字符串
29 // context: 上下文
30 // results: 结果集
31 // seed: 种子
32
33 var Sizzle = function( selector, context, results, seed ) {
34 results = results || []; // 设置默认结果集为空
35 context = context || document; //设置上下文为document对象
36
37 var origContext = context;
38 //如果上下文不是元素和文档对象,则返回空集合
39 if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
40 return [];
41 }
42 //如果选择器参数不存在,或者不为字符串类型,则返回默认结果集
43 if ( !selector || typeof selector !== "string" ) {
44 return results;
45 }
46 //初始化变量
47 var m, set, checkSet, extra, ret, cur, pop, i,
48 prune = true,
49 contextXML = Sizzle.isXML( context ),
50 parts = [],
51 soFar = selector;
52
53 // 重置chunker正则表达式匹配的起始位置为开始位置
54 do {
55 chunker.exec( "" );
56 m = chunker.exec( soFar );
57
58 if ( m ) {
59 soFar = m[3];
60 //存储匹配的字符串信息
61 parts.push( m[1] );
62 //如果是选择符组,则获取后半部分
63 if ( m[2] ) {
64 extra = m[3];
65 break;
66 }
67 }
68 } while ( m );
69 //Expr和Sizzle.selector指向同一个对象,这个选择器对象与老版本不一样,
70 //放弃了if else语句判断,全部使用正则表达式进行处理,执行效率提高了很多,
71 //具体代码参阅Expr对象
72 //POS:正则表达式/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
73 //下面代码判断选择符字符串是否存在特殊函数
74 if ( parts.length > 1 && origPOS.exec( selector ) ) {
75 //relative是函数对象,封装了+>~函数,表示typeof Expr.relative[parts[0]] == Function
76 if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
77 set = posProcess( parts[0] + parts[1], context );
78
79 } else {
80 set = Expr.relative[ parts[0] ] ?
81 [ context ] :
82 Sizzle( parts.shift(), context );
83 //如果匹配到>+~,过滤上下文,去掉选择器中符号,再分析选择器
84 while ( parts.length ) {
85 selector = parts.shift();
86
87 if ( Expr.relative[ selector ] ) {
88 selector += parts.shift();
89 }
90
91 set = posProcess( selector, set );
92 }
93 }
94
95 } else {
96 // Take a shortcut and set the context if the root selector is an ID
97 // (but not if it'll be faster if the inner selector is an ID)
98 if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
99 Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
100
101 ret = Sizzle.find( parts.shift(), context, contextXML );
102 context = ret.expr ?
103 Sizzle.filter( ret.expr, ret.set )[0] :
104 ret.set[0];
105 }
106
107 if ( context ) {
108 //执行种子操作
109 ret = seed ?
110 { expr: parts.pop(), set: makeArray(seed) } :
111 Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
112
113 set = ret.expr ?
114 Sizzle.filter( ret.expr, ret.set ) :
115 ret.set;
116
117 if ( parts.length > 0 ) {
118 checkSet = makeArray( set );
119
120 } else {
121 prune = false;
122 }
123
124 while ( parts.length ) {
125 cur = parts.pop();
126 pop = cur;
127
128 if ( !Expr.relative[ cur ] ) {
129 cur = "";
130 } else {
131 pop = parts.pop();
132 }
133
134 if ( pop == null ) {
135 pop = context;
136 }
137
138 Expr.relative[ cur ]( checkSet, pop, contextXML );
139 }
140
141 } else {
142 checkSet = parts = [];
143 }
144 }
145 //设置默认值
146 if ( !checkSet ) {
147 checkSet = set;
148 }
149
150 if ( !checkSet ) {
151 Sizzle.error( cur || selector );
152 }
153 //如果检测到选项checkSet是数组,则执行下面操作
154 if ( toString.call(checkSet) === "[object Array]" ) {
155 //如果checkSet没有包含set选项值
156 if ( !prune ) {
157 //则把checkSet推入到结果集中
158 results.push.apply( results, checkSet );
159 //如果上下文是元素类型的对象
160 } else if ( context && context.nodeType === 1 ) {
161 //则遍历检测选项集,然后把set推入结果集中
162 for ( i = 0; checkSet[i] != null; i++ ) {
163 if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
164 results.push( set[i] );
165 }
166 }
167
168 } else {
169 for ( i = 0; checkSet[i] != null; i++ ) {
170 if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
171 results.push( set[i] );
172 }
173 }
174 }
175
176 } else {
177 //把结果集与检测选项组合并为数组
178 makeArray( checkSet, results );
179 }
180 //处理组选择器中下一个选择器
181 if ( extra ) {
182 //把后半部分选择器字符串再次传递给构造器,执行下一次匹配处理
183 Sizzle( extra, origContext, results, seed );
184 Sizzle.uniqueSort( results );
185 }
186
187 return results;
188 };











































































































































转载于:https://www.cnblogs.com/spemoon/archive/2011/10/17/2215479.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/230529.html原文链接:https://javaforall.net

(0)
上一篇 2026年2月17日 下午7:01
下一篇 2026年2月17日 下午7:22


相关推荐

  • 桌面太单调?一起用Python做个自定义动画挂件,好玩又有趣!「建议收藏」

    桌面太单调?一起用Python做个自定义动画挂件,好玩又有趣!「建议收藏」前言前段时间,写了篇博客关于Python自制一款炫酷音乐播放器。有粉丝问我,音乐播放器为什么要用PyQt5,效果是不是比Tkinter赞?PyQt5真的可以实现这些炫酷的UI画面吗?之前没接触过PyQt5,能不能多分享一些这方面的开发案例?今天就带大家,一起用Python的PyQt5开发一个有趣的自定义桌面动画挂件,看看实现的动画挂件效果!下面,我们开始介绍这个自定义桌面动画挂件的制作过程。一、核心功能设计总体来说,我们需要实现将自己喜欢的动态图gif或者视频转成一个桌面动画挂件,并且可以通过鼠

    2022年4月25日
    31
  • 智谱 GLM 网页读取MCP:你能立即上手的4个小而美的AI实战技巧

    智谱 GLM 网页读取MCP:你能立即上手的4个小而美的AI实战技巧

    2026年3月12日
    1
  • 二十、Sql Server 保留几位小数的两种做法

    二十、Sql Server 保留几位小数的两种做法问题:数据库里的floatmomey类型,都会精确到多位小数。但有时候我们不需要那么精确,例如,只精确到两位有效数字。解决:1.使用Round()函数,如Round(@num,2)参数2表示保留两位有效数字。2.更好的方法是使用Convert(decimal(18,2),@num)实现转换,decimal(18,2)…

    2022年7月20日
    33
  • Linux系统查看CPU使用率、内存使用率、磁盘使用率

    Linux系统查看CPU使用率、内存使用率、磁盘使用率一 查看 CPU 使用率 1 top 命令 top 命令可以看到总体的系统运行状态和 cpu 的使用率 us 表示用户空间程序的 cpu 使用率 没有通过 nice 调度 sy 表示系统空间的 cpu 使用率 主要是内核程序 ni 表示用户空间且通过 nice 调度过的程序的 cpu 使用率 id 空闲 cpu wa cpu 运行时在等待 io 的时间 hi cpu 处理硬中断的数量 si cpu 处理软中断

    2026年3月19日
    2
  • offset宏定义_vba offset 用法

    offset宏定义_vba offset 用法C语言面试的时候可能会考,这样的宏定义:#defineoffsetof(TYPE,MEMBER)((size_t)&((TYPE*)0)->MEMBER)函数作用:计算结构体成员的偏移,有些自有代码里也会手写这样的代码,实际上这个函数是标准实现的。实际上如果我们浏览ANSIC编译器的标头文件,将在stddef.h中遇到这样奇怪的宏。这个红具有可怕的声明。此…

    2022年8月22日
    6
  • 8421BCD码与十进制之间的转换

    8421BCD码与十进制之间的转换BCD 码也叫二进制编码的十进制数 就是为了方便二进制与十进制的转换而定义的 如无特殊说明 BCD 码指 8421BCD 码 1 BCD 码每四位表示十进制中的一位的二进制表示 BCD 码转换为十进制同理 从右往左每四位按二进制转换为十进制 2 因为 4 位二进制有 0 到 15 共 16 个数 而十进制中只有 0 到 9 共 10 个数 所以 BCD 码中每四位有 6 个无效码 即 1010 到 1111 在进行 BCD 码加法运算时 如果运算结果处于无效码区间 则需要将运算结果 6 0110 多位数加法同理 注意 如果出现无效码的地方不是在最后一位 就不

    2026年3月18日
    1

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号