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 };


posted @ 2011-10-17 15:46  spemoon  阅读(375)  评论(0编辑  收藏  举报