jquery--选择器sizzle源码分析
生活随笔
收集整理的這篇文章主要介紹了
jquery--选择器sizzle源码分析
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
1 (function( window, undefined ) {
2
3 var i,
4 cachedruns,//正在匹配第幾個(gè)元素
5 Expr, //Sizzle.selectors的快捷方式
6 getText,//獲取文本函數(shù)
7 isXML, //是否為xml
8 compile,//編譯函數(shù)
9 outermostContext,
10 recompare,
11 sortInput,
12
13 // Local document vars
14 setDocument,
15 document,//這里只是document是個(gè)普通的變量,需要setDocument函數(shù)賦值處理過的真正的document
16 docElem,
17 documentIsHTML,
18 rbuggyQSA,//支持的querySelectorAll選擇器正則(rbuggyQSA = new RegExp( rbuggyQSA.join("|") );)
19 rbuggyMatches,//支持matchesSelector正則(rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );)
20 matches,//matchesSelector函數(shù)
21 contains,
22
23 // Instance-specific data
24 expando = "sizzle" + -(new Date()),
25 preferredDoc = window.document,//全局的document
26 support = {},
27 dirruns = 0,
28 done = 0,//第幾個(gè)關(guān)系選擇器匹配函數(shù)
29 classCache = createCache(),
30 tokenCache = createCache(),
31 compilerCache = createCache(),
32 hasDuplicate = false,
33 sortOrder = function() { return 0; },
34
35 // General-purpose constants
36 strundefined = typeof undefined,
37 MAX_NEGATIVE = 1 << 31,
38
39 // Array methods
40 arr = [],
41 pop = arr.pop,
42 push_native = arr.push,
43 push = arr.push,
44 slice = arr.slice,
45 // Use a stripped-down indexOf if we can't use a native one
46 //如果數(shù)組原生不支持indexOf,我們自己定義。獲取元素在數(shù)組中的位置
47 indexOf = arr.indexOf || function( elem ) {
48 var i = 0,
49 len = this.length;
50 for ( ; i < len; i++ ) {
51 if ( this[i] === elem ) {
52 return i;
53 }
54 }
55 return -1;
56 },
57
58
59 //正則表達(dá)式
60
61 //空白字符正則字符串
62 whitespace = "[\\x20\\t\\r\\n\\f]",
63 //字符編碼正則字符串
64 characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
65
66 identifier = characterEncoding.replace( "w", "w#" ),
67
68 //可用的屬性操作符
69 operators = "([*^$|!~]?=)",
70 //屬性選擇器正則
71 ///^\[whitespace*(characterEncoding)whitespace*(?:([*^$|!~]?=)whitespace*(?:(['"])((?:\\.|[^\\])*?)\3|((?:\\.|[\w#-]|[^\x00-\xa0])+)|)|)whitespace*\]/
72 attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
73 "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
74
75 //偽類正則字符串
76 pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
77
78 // 去掉兩端空白和字符串中的反斜杠(如果連續(xù)兩個(gè)去掉一個(gè))正則
79 rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
80 //并聯(lián)選擇器的正則
81 rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
82 //關(guān)系選擇器正則
83 rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ),
84 //偽類正則字符串
85 rpseudo = new RegExp( pseudos ),
86 ridentifier = new RegExp( "^" + identifier + "$" ),
87
88 matchExpr = {
89 "ID": new RegExp( "^#(" + characterEncoding + ")" ),
90 "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
91 "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ),
92 "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
93 "ATTR": new RegExp( "^" + attributes ),
94 "PSEUDO": new RegExp( "^" + pseudos ),
95 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
96 "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
97 "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
98 //開始為>+~或位置偽類,如果選擇器中有位置偽類解析從左往右
99 "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
100 whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
101 },
102 //弟兄正則
103 rsibling = /[\x20\t\r\n\f]*[+~]/,
104 //原生函數(shù)正則
105 rnative = /^[^{]+\{\s*\[native code/,
106
107 //僅僅單個(gè)id或tag、class選擇器正則(用來快速解析并獲取元素)
108 rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
109 //jQuery自定義的偽類,它們不是的CSS規(guī)范的一部分,使用它們查詢不能充分利用原生DOM提供的querySelectorAll() 方法來提高性能。為了在現(xiàn)代瀏覽器上獲得更佳的性能,請(qǐng)使用 .filter(":input")代替。
110 rinputs = /^(?:input|select|textarea|button)$/i,
111 //同上
112 rheader = /^h\d$/i,
113
114 rescape = /'|\\/g,
115 //屬性沒帶引號(hào)正則
116 rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
117
118 //css轉(zhuǎn)義,配合funescape使用 如:string.replace(runescape, funescape);
119 runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,
120 funescape = function( _, escaped ) {
121 var high = "0x" + escaped - 0x10000;
122 // NaN means non-codepoint
123 return high !== high ?
124 escaped :
125 // BMP codepoint
126 high < 0 ?
127 String.fromCharCode( high + 0x10000 ) :
128 // Supplemental Plane codepoint (surrogate pair)
129 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
130 };
131
132 //把NodeList轉(zhuǎn)換為數(shù)組,因?yàn)閿?shù)組比集合效率高
133 try {
134 push.apply(
135 (arr = slice.call( preferredDoc.childNodes )),
136 preferredDoc.childNodes
137 );
138 // Support: Android<4.0
139 // Detect silently failing push.apply
140 arr[ preferredDoc.childNodes.length ].nodeType;
141 } catch ( e ) {
142 push = { apply: arr.length ?
143
144 // Leverage slice if possible
145 function( target, els ) {
146 push_native.apply( target, slice.call(els) );
147 } :
148
149 // Support: IE<9
150 // Otherwise append directly
151 function( target, els ) {
152 var j = target.length,
153 i = 0;
154 // Can't trust NodeList.length
155 while ( (target[j++] = els[i++]) ) {}
156 target.length = j - 1;
157 }
158 };
159 }
160
161 //測試是否是原生函數(shù)
162 function isNative( fn ) {
163 return rnative.test( fn + "" );
164 }
165
166 //創(chuàng)建緩存函數(shù)(緩存大小默認(rèn)為50,可以自己設(shè)置)
167 //這里利用了閉包(私有變量、變量一直保存在內(nèi)存中)
168 function createCache() {
169 var cache,
170 keys = [];
171
172 return (cache = function( key, value ) {
173 // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
174 if ( keys.push( key += " " ) > Expr.cacheLength ) {
175 // Only keep the most recent entries
176 delete cache[ keys.shift() ];
177 }
178 return (cache[ key ] = value);
179 });
180 }
181
182 //標(biāo)記函數(shù)供sizzle特殊用途
183 function markFunction( fn ) {
184 fn[ expando ] = true;
185 return fn;
186 }
187
188 // 用于做各種特征檢測,比如是否支持某個(gè)API,API支持是否完美
189
190 function assert( fn ) {
191 var div = document.createElement("div");
192
193 try {
194 return !!fn( div );
195 } catch (e) {
196 return false;
197 } finally {
198 // release memory in IE
199 div = null;
200 }
201 }
202
203 //sizzle主函數(shù)
204 //selector css選擇器, context上下文,results結(jié)果集,seed篩選集
205
206 function Sizzle( selector, context, results, seed ) {
207 var match, elem, m, nodeType,
208 // QSA vars
209 i, groups, old, nid, newContext, newSelector;
210
211 if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
212 setDocument( context );
213 }
214
215 context = context || document;
216 results = results || [];
217
218 if ( !selector || typeof selector !== "string" ) {
219 return results;
220 }
221
222 if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
223 return [];
224 }
225
226 if ( documentIsHTML && !seed ) {
227
228 // Shortcuts
229 // 如果僅僅是id或class或tag用原生函數(shù)
230 if ( (match = rquickExpr.exec( selector )) ) {
231 // Speed-up: Sizzle("#ID")
232 if ( (m = match[1]) ) {
233 if ( nodeType === 9 ) {
234 elem = context.getElementById( m );
235 // Check parentNode to catch when Blackberry 4.6 returns
236 // nodes that are no longer in the document #6963
237 if ( elem && elem.parentNode ) {
238 // Handle the case where IE, Opera, and Webkit return items
239 // by name instead of ID
240 if ( elem.id === m ) {
241 results.push( elem );
242 return results;
243 }
244 } else {
245 return results;
246 }
247 } else {
248 // Context is not a document
249 if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
250 contains( context, elem ) && elem.id === m ) {
251 results.push( elem );
252 return results;
253 }
254 }
255
256 // Speed-up: Sizzle("TAG")
257 } else if ( match[2] ) {
258 push.apply( results, context.getElementsByTagName( selector ) );
259 return results;
260
261 // Speed-up: Sizzle(".CLASS")
262 } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
263 push.apply( results, context.getElementsByClassName( m ) );
264 return results;
265 }
266 }
267
268 // QSA path
269 //使用querySelectorAll
270 if ( !support.qsa && !rbuggyQSA.test(selector) ) {
271 old = true;
272 nid = expando;
273 newContext = context;
274 newSelector = nodeType === 9 && selector;
275
276 // qSA works strangely on Element-rooted queries
277 // We can work around this by specifying an extra ID on the root
278 // and working up from there (Thanks to Andrew Dupont for the technique)
279 // IE 8 doesn't work on object elements
280 if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
281 groups = tokenize( selector );
282
283 if ( (old = context.getAttribute("id")) ) {
284 nid = old.replace( rescape, "\\$&" );
285 } else {
286 context.setAttribute( "id", nid );
287 }
288 nid = "[id='" + nid + "'] ";
289
290 i = groups.length;
291 while ( i-- ) {
292 groups[i] = nid + toSelector( groups[i] );
293 }
294 newContext = rsibling.test( selector ) && context.parentNode || context;
295 newSelector = groups.join(",");
296 }
297
298 if ( newSelector ) {
299 try {
300 push.apply( results,
301 newContext.querySelectorAll( newSelector )
302 );
303 return results;
304 } catch(qsaError) {
305 } finally {
306 if ( !old ) {
307 context.removeAttribute("id");
308 }
309 }
310 }
311 }
312 }
313
314 // All others
315 return select( selector.replace( rtrim, "$1" ), context, results, seed );
316 }
317
318 //檢測是否為xml
319 isXML = Sizzle.isXML = function( elem ) {
320 // documentElement is verified for cases where it doesn't yet exist
321 // (such as loading iframes in IE - #4833)
322 var documentElement = elem && (elem.ownerDocument || elem).documentElement;
323 return documentElement ? documentElement.nodeName !== "HTML" : false;
324 };
325
326
327 //根據(jù)當(dāng)前的document設(shè)置document相關(guān)的變量(只設(shè)置一次)
328 setDocument = Sizzle.setDocument = function( node ) {
329 var doc = node ? node.ownerDocument || node : preferredDoc;
330
331 //如果document已經(jīng)設(shè)置了返回(這里document是個(gè)變量初始值是undefined)
332 //不是文檔對(duì)象返回
333 //文檔對(duì)象沒有返回根節(jié)點(diǎn)時(shí)返回
334 if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
335 return document;
336 }
337
338 //給document變量設(shè)置真正的文檔
339 document = doc;
340 docElem = doc.documentElement;
341
342 documentIsHTML = !isXML( doc );
343
344 //檢查getElementsByTagName是否會(huì)返回注釋節(jié)點(diǎn),IE6-8會(huì)混雜注釋節(jié)點(diǎn)
345 support.getElementsByTagName = assert(function( div ) {
346 div.appendChild( doc.createComment("") );
347 return !div.getElementsByTagName("*").length;
348 });
349
350 // Check if attributes should be retrieved by attribute nodes
351 support.attributes = assert(function( div ) {
352 div.innerHTML = "<select></select>";
353 var type = typeof div.lastChild.getAttribute("multiple");
354 // IE8 returns a string for some attributes even when not present
355 return type !== "boolean" && type !== "string";
356 });
357
358 //檢查getElementsByClassName是否100%支持
359 support.getElementsByClassName = assert(function( div ) {
360 //Oprea9.6不可以發(fā)現(xiàn)第二個(gè)className
361 div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>";
362 if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) {
363 return false;
364 }
365
366 //safari3.2緩存了class屬性,所以不能獲取改變過的classname
367 div.lastChild.className = "e";
368 return div.getElementsByClassName("e").length === 2;
369 });
370
371 //檢查getElementByName
372 support.getByName = assert(function( div ) {
373 // Inject content
374 div.id = expando + 0;
375 // Support: Windows 8 Native Apps
376 // Assigning innerHTML with "name" attributes throws uncatchable exceptions
377 // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx
378 // getElementsByName是一個(gè)問題多的API
379 //1 IE6-7下getElementsByName與getElementById都不區(qū)分元素的name與ID
380 //2 IE的getElementsByName只對(duì)表單元素有效,無視擁有相同name值的span div元素
381 //3 IE6-7下即使通過document.createElement創(chuàng)建一個(gè)表單元素,動(dòng)態(tài)設(shè)置name與插入
382 // DOM樹,getElementsByName無法找到此元素,innerHTML也不行。一定需要以
383 // document.createElement("<input name="aaa"/>")方式生成元素才行。
384 // 同樣的情況也發(fā)生在iframe上,IE6-7的iframe的name也需要這樣同時(shí)生成。
385 //4 name本來是一個(gè)property,但標(biāo)準(zhǔn)瀏覽器好像已經(jīng)默認(rèn)setAttribute("name","xxx")
386 // 也能被getElementsByName獲取到。
387 //5 IE6-8通過innerHTML生成包含name屬性的元素時(shí),可能發(fā)生無法捕獲的錯(cuò)誤
388 div.appendChild( document.createElement("a") ).setAttribute( "name", expando );
389 div.appendChild( document.createElement("i") ).setAttribute( "name", expando );
390 docElem.appendChild( div );
391
392 // Test
393 var pass = doc.getElementsByName &&
394 // buggy browsers will return fewer than the correct 2
395 doc.getElementsByName( expando ).length === 2 +
396 // buggy browsers will return more than the correct 0
397 doc.getElementsByName( expando + 0 ).length;
398
399 // Cleanup
400 docElem.removeChild( div );
401
402 return pass;
403 });
404
405 // Support: Webkit<537.32
406 // Detached nodes confoundingly follow *each other*
407 support.sortDetached = assert(function( div1 ) {
408 return div1.compareDocumentPosition &&
409 // Should return 1, but Webkit returns 4 (following)
410 (div1.compareDocumentPosition( document.createElement("div") ) & 1);
411 });
412
413 //ie6/7 href和type屬性獲取
414 Expr.attrHandle = assert(function( div ) {
415 div.innerHTML = "<a href='#'></a>";
416 return div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&
417 div.firstChild.getAttribute("href") === "#";
418 }) ?
419 {} :
420 {
421 "href": function( elem ) {
422 return elem.getAttribute( "href", 2 );
423 },
424 "type": function( elem ) {
425 return elem.getAttribute("type");
426 }
427 };
428
429 //查找id節(jié)點(diǎn)和節(jié)點(diǎn)id是否匹配過濾函數(shù)
430 if ( support.getByName ) {
431 Expr.find["ID"] = function( id, context ) {
432 if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
433 var m = context.getElementById( id );
434 // Check parentNode to catch when Blackberry 4.6 returns
435 // nodes that are no longer in the document #6963
436 //Blackberry 4.6 緩存過度,即便這元素被移出DOM樹也能找到
437 return m && m.parentNode ? [m] : [];
438 }
439 };
440 Expr.filter["ID"] = function( id ) {
441 var attrId = id.replace( runescape, funescape );
442 return function( elem ) {
443 return elem.getAttribute("id") === attrId;
444 };
445 };
446 } else {
447 Expr.find["ID"] = function( id, context ) {
448 if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
449 var m = context.getElementById( id );
450
451 return m ?
452 m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
453 [m] :
454 undefined :
455 [];
456 }
457 };
458 Expr.filter["ID"] = function( id ) {
459 var attrId = id.replace( runescape, funescape );
460 return function( elem ) {
461 var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
462 return node && node.value === attrId;
463 };
464 };
465 }
466
467 //根據(jù)標(biāo)簽查找節(jié)點(diǎn)
468 Expr.find["TAG"] = support.getElementsByTagName ?
469 function( tag, context ) {
470 if ( typeof context.getElementsByTagName !== strundefined ) {
471 return context.getElementsByTagName( tag );
472 }
473 } :
474 function( tag, context ) {
475 var elem,
476 tmp = [],
477 i = 0,
478 results = context.getElementsByTagName( tag );
479
480 // Filter out possible comments
481 if ( tag === "*" ) {
482 while ( (elem = results[i++]) ) {
483 if ( elem.nodeType === 1 ) {
484 tmp.push( elem );
485 }
486 }
487
488 return tmp;
489 }
490 return results;
491 };
492
493 //如果支持根據(jù)name查找節(jié)點(diǎn)
494 Expr.find["NAME"] = support.getByName && function( tag, context ) {
495 if ( typeof context.getElementsByName !== strundefined ) {
496 return context.getElementsByName( name );
497 }
498 };
499
500 //如果支持根據(jù)class查找節(jié)點(diǎn)
501 Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
502 if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
503 return context.getElementsByClassName( className );
504 }
505 };
506
507 // QSA and matchesSelector support
508
509 rbuggyMatches = [];//支持的matchesSelector放到數(shù)組中
510
511 rbuggyQSA = [ ":focus" ];//支持的querySelectorAll放到數(shù)組中
512
513 if ( (support.qsa = isNative(doc.querySelectorAll)) ) {
514 // Build QSA regex
515 // Regex strategy adopted from Diego Perini
516 assert(function( div ) {
517 // Select is set to empty string on purpose
518 // This is to test IE's treatment of not explicitly
519 // setting a boolean content attribute,
520 // since its presence should be enough
521 // http://bugs.jquery.com/ticket/12359
522 div.innerHTML = "<select><option selected=''></option></select>";
523
524 // IE8 - Some boolean attributes are not treated correctly
525 if ( !div.querySelectorAll("[selected]").length ) {
526 rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" );
527 }
528
529 // Webkit/Opera - :checked should return selected option elements
530 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
531 // IE8 throws error here and will not see later tests
532 if ( !div.querySelectorAll(":checked").length ) {
533 rbuggyQSA.push(":checked");
534 }
535 });
536
537 assert(function( div ) {
538
539 // Opera 10-12/IE8 - ^= $= *= and empty values
540 // Should not select anything
541 div.innerHTML = "<input type='hidden' i=''/>";
542 if ( div.querySelectorAll("[i^='']").length ) {
543 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" );
544 }
545
546 // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
547 // IE8 throws error here and will not see later tests
548 if ( !div.querySelectorAll(":enabled").length ) {
549 rbuggyQSA.push( ":enabled", ":disabled" );
550 }
551
552 // Opera 10-11 does not throw on post-comma invalid pseudos
553 div.querySelectorAll("*,:x");
554 rbuggyQSA.push(",.*:");
555 });
556 }
557
558 if ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector ||
559 docElem.mozMatchesSelector ||
560 docElem.webkitMatchesSelector ||
561 docElem.oMatchesSelector ||
562 docElem.msMatchesSelector) )) ) {
563
564 assert(function( div ) {
565 //ie9能匹配移出DOM樹的節(jié)點(diǎn)
566 support.disconnectedMatch = matches.call( div, "div" );
567
568 //Gecko對(duì)于非法選擇符不會(huì)拋錯(cuò),而是返回false
569 matches.call( div, "[s!='']:x" );
570 rbuggyMatches.push( "!=", pseudos );
571 });
572 }
573
574 rbuggyQSA = new RegExp( rbuggyQSA.join("|") );
575 rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
576
577 // Element contains another
578 // Purposefully does not implement inclusive descendent
579 // As in, an element does not contain itself
580 contains = isNative(docElem.contains) || docElem.compareDocumentPosition ?
581 function( a, b ) {
582 var adown = a.nodeType === 9 ? a.documentElement : a,
583 bup = b && b.parentNode;
584 return a === bup || !!( bup && bup.nodeType === 1 && (
585 adown.contains ?
586 adown.contains( bup ) :
587 a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
588 ));
589 } :
590 function( a, b ) {
591 if ( b ) {
592 while ( (b = b.parentNode) ) {
593 if ( b === a ) {
594 return true;
595 }
596 }
597 }
598 return false;
599 };
600
601 //文檔順序排序
602 sortOrder = docElem.compareDocumentPosition ?
603 function( a, b ) {
604
605 //重復(fù)刪除標(biāo)記
606 if ( a === b ) {
607 hasDuplicate = true;
608 return 0;
609 }
610
611 var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b );
612
613 if ( compare ) {
614 // Disconnected nodes
615 if ( compare & 1 ||
616 (recompare && b.compareDocumentPosition( a ) === compare) ) {
617
618 // Choose the first element that is related to our preferred document
619 if ( a === doc || contains(preferredDoc, a) ) {
620 return -1;
621 }
622 if ( b === doc || contains(preferredDoc, b) ) {
623 return 1;
624 }
625
626 // Maintain original order
627 return sortInput ?
628 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
629 0;
630 }
631
632 return compare & 4 ? -1 : 1;
633 }
634
635 //不能直接比較,sort上不存在這個(gè)方法
636 return a.compareDocumentPosition ? -1 : 1;
637 } :
638 function( a, b ) {
639 var cur,
640 i = 0,
641 aup = a.parentNode,
642 bup = b.parentNode,
643 ap = [ a ],
644 bp = [ b ];
645
646 // Exit early if the nodes are identical
647 if ( a === b ) {
648 hasDuplicate = true;
649 return 0;
650
651 // Parentless nodes are either documents or disconnected
652 } else if ( !aup || !bup ) {
653 return a === doc ? -1 :
654 b === doc ? 1 :
655 aup ? -1 :
656 bup ? 1 :
657 0;
658
659 // If the nodes are siblings, we can do a quick check
660 } else if ( aup === bup ) {
661 return siblingCheck( a, b );
662 }
663
664 // Otherwise we need full lists of their ancestors for comparison
665 cur = a;
666 while ( (cur = cur.parentNode) ) {
667 ap.unshift( cur );
668 }
669 cur = b;
670 while ( (cur = cur.parentNode) ) {
671 bp.unshift( cur );
672 }
673
674 // Walk down the tree looking for a discrepancy
675 while ( ap[i] === bp[i] ) {
676 i++;
677 }
678
679 return i ?
680 // Do a sibling check if the nodes have a common ancestor
681 siblingCheck( ap[i], bp[i] ) :
682
683 // Otherwise nodes in our document sort first
684 ap[i] === preferredDoc ? -1 :
685 bp[i] === preferredDoc ? 1 :
686 0;
687 };
688
689 return document;
690 };
691 //篩選匹配的elements
692 Sizzle.matches = function( expr, elements ) {
693 return Sizzle( expr, null, null, elements );
694 };
695
696 Sizzle.matchesSelector = function( elem, expr ) {
697 // Set document vars if needed
698 if ( ( elem.ownerDocument || elem ) !== document ) {
699 setDocument( elem );
700 }
701
702 //確保屬性選擇器有引號(hào)(querySelectorAll需要有引號(hào))
703 expr = expr.replace( rattributeQuotes, "='$1']" );
704
705 //rbuggyQSA中肯定存在:focus,所以不需要檢查是否存在
706 if ( support.matchesSelector && documentIsHTML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) {
707 try {
708 var ret = matches.call( elem, expr );
709
710 //ie9和文檔分離的node返回false
711 //同樣在ie9中文檔片段也是分離的節(jié)點(diǎn)(createElement('div')這樣創(chuàng)建的節(jié)點(diǎn)有document屬性.document.nodeType為11)
712 if ( ret || support.disconnectedMatch || elem.document && elem.document.nodeType !== 11 ) {
713 return ret;
714 }
715 } catch(e) {}
716 }
717
718 return Sizzle( expr, document, null, [elem] ).length > 0;
719 };
720
721 Sizzle.contains = function( context, elem ) {
722 // Set document vars if needed
723 if ( ( context.ownerDocument || context ) !== document ) {
724 setDocument( context );
725 }
726 return contains( context, elem );
727 };
728
729 Sizzle.attr = function( elem, name ) {
730 var val;
731
732 // Set document vars if needed
733 if ( ( elem.ownerDocument || elem ) !== document ) {
734 setDocument( elem );
735 }
736
737 if ( documentIsHTML ) {
738 name = name.toLowerCase();
739 }
740 if ( (val = Expr.attrHandle[ name ]) ) {
741 return val( elem );
742 }
743 if ( !documentIsHTML || support.attributes ) {
744 return elem.getAttribute( name );
745 }
746 return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ?
747 name :
748 val && val.specified ? val.value : null;
749 };
750
751 Sizzle.error = function( msg ) {
752 throw new Error( "Syntax error, unrecognized expression: " + msg );
753 };
754
755 //排序并去重
756 Sizzle.uniqueSort = function( results ) {
757 var elem,
758 duplicates = [],
759 j = 0,
760 i = 0;
761
762 // Unless we *know* we can detect duplicates, assume their presence
763 //除非我們知道我們可以檢測到重復(fù)的,假設(shè)他們的存在
764 hasDuplicate = !support.detectDuplicates;
765 // Compensate for sort limitations
766 recompare = !support.sortDetached;
767 sortInput = !support.sortStable && results.slice( 0 );
768 results.sort( sortOrder );
769
770 if ( hasDuplicate ) {
771 while ( (elem = results[i++]) ) {
772 if ( elem === results[ i ] ) {
773 j = duplicates.push( i );
774 }
775 }
776 while ( j-- ) {
777 results.splice( duplicates[ j ], 1 );
778 }
779 }
780
781 return results;
782 };
783
784 // 兄弟節(jié)點(diǎn)排序
785
786 function siblingCheck( a, b ) {
787 var cur = b && a,
788 diff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE );
789
790 // Use IE sourceIndex if available on both nodes
791 if ( diff ) {
792 return diff;
793 }
794
795 // Check if b follows a
796 if ( cur ) {
797 while ( (cur = cur.nextSibling) ) {
798 if ( cur === b ) {
799 return -1;
800 }
801 }
802 }
803
804 return a ? 1 : -1;
805 }
806
807 //創(chuàng)建一個(gè)偽類的過濾函數(shù),此方法是根據(jù)表單元素的type值生成
808 //比如:radio, :text, :checkbox, :file, :image等自定義偽類
809 function createInputPseudo( type ) {
810 return function( elem ) {
811 var name = elem.nodeName.toLowerCase();
812 return name === "input" && elem.type === type;
813 };
814 }
815
816 //創(chuàng)建一個(gè)偽類的過濾函數(shù),此方法是根據(jù)表單元素的type值或標(biāo)簽類型生成
817 //如果:button, :submit自定義偽類
818 function createButtonPseudo( type ) {
819 return function( elem ) {
820 var name = elem.nodeName.toLowerCase();
821 return (name === "input" || name === "button") && elem.type === type;
822 };
823 }
824
825 //用于創(chuàng)建位置偽類的過濾函數(shù),它們是模擬從左向右的順序進(jìn)行選擇,
826 //匹配到它時(shí)的結(jié)果集的位置來挑選元素的
827 //比如:odd,:even, :eq, :gt, :lt, :first, :last
828 function createPositionalPseudo( fn ) {
829 return markFunction(function( argument ) {
830 argument = +argument;
831 return markFunction(function( seed, matches ) {
832 var j,
833 matchIndexes = fn( [], seed.length, argument ),
834 i = matchIndexes.length;
835
836 // Match elements found at the specified indexes
837 while ( i-- ) {
838 if ( seed[ (j = matchIndexes[i]) ] ) {
839 seed[j] = !(matches[j] = seed[j]);//這里的j是數(shù)組索引值,matches數(shù)組中可能會(huì)出現(xiàn)undefinde值 如:var arr = []; arr[10] = 10;這里前9項(xiàng)會(huì)是undefined
840 }
841 }
842 });
843 });
844 }
845
846 //工具函數(shù)用于獲取給定節(jié)點(diǎn)的text
847 getText = Sizzle.getText = function( elem ) {
848 var node,
849 ret = "",
850 i = 0,
851 nodeType = elem.nodeType;
852
853 if ( !nodeType ) {
854 // If no nodeType, this is expected to be an array
855 for ( ; (node = elem[i]); i++ ) {
856 // Do not traverse comment nodes
857 ret += getText( node );
858 }
859 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
860 // Use textContent for elements
861 // innerText usage removed for consistency of new lines (see #11153)
862 if ( typeof elem.textContent === "string" ) {
863 return elem.textContent;
864 } else {
865 // Traverse its children
866 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
867 ret += getText( elem );
868 }
869 }
870 } else if ( nodeType === 3 || nodeType === 4 ) {
871 return elem.nodeValue;
872 }
873 // Do not include comment or processing instruction nodes
874
875 return ret;
876 };
877
878 Expr = Sizzle.selectors = {
879
880 // Can be adjusted by the user
881 cacheLength: 50,
882
883 createPseudo: markFunction,
884
885 match: matchExpr,
886
887 find: {},//查找元素
888
889 relative: {
890 ">": { dir: "parentNode", first: true },
891 " ": { dir: "parentNode" },
892 "+": { dir: "previousSibling", first: true },
893 "~": { dir: "previousSibling" }
894 },
895
896 preFilter: {//正則出來的數(shù)組不能直接用需要過濾下如:attr正則出來的數(shù)組引號(hào)還有~=
897 "ATTR": function( match ) {
898 match[1] = match[1].replace( runescape, funescape );
899
900 //不管有沒有引號(hào)都把value值移到match[3]
901 //有引號(hào)["[name="username"]", "name", "=", """, "username", undefined]
902 //無引號(hào)["[name=username]", "name", "=", undefined, undefined, "username"]
903 match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
904
905 if ( match[2] === "~=" ) {//匹配屬性值必須有空格分隔(這個(gè)選擇器測試屬性值中的每個(gè)單詞字符串,其中“word”是一個(gè)由空白分隔的字符串定義的)
906 match[3] = " " + match[3] + " ";
907 }
908
909 return match.slice( 0, 4 );
910 },
911
912 "CHILD": function( match ) {
913 /* matches from matchExpr["CHILD"]
914 1 type (only|nth|...)
915 2 what (child|of-type)
916 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
917 4 xn-component of xn+y argument ([+-]?\d*n|)
918 5 sign of xn-component
919 6 x of xn-component
920 7 sign of y-component
921 8 y of y-component
922 */
923 //[":nth-child(2n + 1)", "nth", "child", "2n + 1", "2n", "", "2", "+", "1"]
924 //[":nth-last-child(1)", "nth-last", "child", "1", "", undefined, undefined, "", "1"]
925 //[":nth-child(even)", "nth", "child", "even", undefined, undefined, undefined, undefined, undefined]
926 match[1] = match[1].toLowerCase();
927 //當(dāng)選擇器中有nth時(shí)
928 if ( match[1].slice( 0, 3 ) === "nth" ) {
929 // nth-* requires argument
930 //當(dāng)選擇器中有nth時(shí)小括號(hào)內(nèi)沒有值說明不是合法的CHILD選擇器
931 if ( !match[3] ) {
932 Sizzle.error( match[0] );
933 }
934
935 // numeric x and y parameters for Expr.filter.CHILD
936 // remember that false/true cast respectively to 0/1
937 //處理(xn + y)
938 //true和false分別轉(zhuǎn)換為1和0, true和false參與運(yùn)算時(shí)會(huì)自動(dòng)轉(zhuǎn)換為1和0
939 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
940 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
941
942 // other types prohibit arguments
943 //如果不是nth類型但是match[3]有值說明不是合法的CHILD選擇器
944 } else if ( match[3] ) {
945 Sizzle.error( match[0] );
946 }
947
948 return match;
949 },
950
951 "PSEUDO": function( match ) {
952 var excess,
953 unquoted = !match[5] && match[2];
954
955 //如果是孩子偽類不處理
956 if ( matchExpr["CHILD"].test( match[0] ) ) {
957 return null;
958 }
959 //[":has(input[name=username])", "has", "input[name=username]", undefined, undefined, "input[name=username]", "name", "=", undefined, undefined, "username"]
960 // Accept quoted arguments as-is
961 //如果小括號(hào)內(nèi)有引號(hào) 如:[":eq("2")", "eq", ""2"", """, "2", undefined, undefined, undefined, undefined, undefined, undefined]
962 if ( match[4] ) {
963 match[2] = match[4];
964
965 // Strip excess characters from unquoted arguments
966 //不知道什么偽類會(huì)走這里
967 } else if ( unquoted && rpseudo.test( unquoted ) &&
968 // Get excess from tokenize (recursively)
969 (excess = tokenize( unquoted, true )) &&
970 // advance to the next closing parenthesis
971 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
972
973 // excess is a negative index
974 match[0] = match[0].slice( 0, excess );
975 match[2] = unquoted.slice( 0, excess );
976 }
977
978 //返回捕獲中僅僅需要的過濾方法(type和argument)
979 return match.slice( 0, 3 );
980 }
981 },
982
983 filter: {//過濾函數(shù)(判斷各節(jié)點(diǎn)是否符合條件)
984
985 "TAG": function( nodeName ) {
986 if ( nodeName === "*" ) {
987 return function() { return true; };
988 }
989
990 nodeName = nodeName.replace( runescape, funescape ).toLowerCase();
991 return function( elem ) {
992 return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
993 };
994 },
995
996 "CLASS": function( className ) {
997 var pattern = classCache[ className + " " ];
998
999 return pattern ||
1000 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
1001 classCache( className, function( elem ) {
1002 return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" );
1003 });
1004 },
1005
1006 "ATTR": function( name, operator, check ) {
1007 return function( elem ) {
1008 var result = Sizzle.attr( elem, name );
1009
1010 if ( result == null ) {
1011 return operator === "!=";
1012 }
1013 if ( !operator ) {
1014 return true;
1015 }
1016
1017 result += "";
1018
1019 return operator === "=" ? result === check :
1020 operator === "!=" ? result !== check :
1021 operator === "^=" ? check && result.indexOf( check ) === 0 :
1022 operator === "*=" ? check && result.indexOf( check ) > -1 :
1023 operator === "$=" ? check && result.slice( -check.length ) === check :
1024 operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
1025 operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
1026 false;
1027 };
1028 },
1029
1030 //:nth-child(2)
1031 //["nth", "child", "2", 0, 2, undefined, "", "2"]
1032 "CHILD": function( type, what, argument, first, last ) {
1033 var simple = type.slice( 0, 3 ) !== "nth", //是否有nth
1034 forward = type.slice( -4 ) !== "last",//是否正向查找
1035 ofType = what === "of-type"; //是否有of-type
1036
1037 return first === 1 && last === 0 ?
1038
1039 // Shortcut for :nth-*(n)
1040 function( elem ) {
1041 return !!elem.parentNode;
1042 } :
1043
1044 function( elem, context, xml ) {
1045 var cache, outerCache, node, diff, nodeIndex, start,
1046 dir = simple !== forward ? "nextSibling" : "previousSibling",
1047 parent = elem.parentNode,
1048 name = ofType && elem.nodeName.toLowerCase(),
1049 useCache = !xml && !ofType;
1050
1051 if ( parent ) {
1052
1053 // :(first|last|only)-(child|of-type)
1054 if ( simple ) {
1055 while ( dir ) {
1056 node = elem;
1057 while ( (node = node[ dir ]) ) {
1058 //如果不是of-type, first如果前面還有元素返回false, last如果后面還有元素返回false
1059 //如果是of-type, name值全等返回false
1060 if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
1061 return false;
1062 }
1063 }
1064 // Reverse direction for :only-* (if we haven't yet done so)
1065 //如果type為only時(shí),
1066 start = dir = type === "only" && !start && "nextSibling";
1067 }
1068 return true;
1069 }
1070
1071 start = [ forward ? parent.firstChild : parent.lastChild ];
1072
1073 // non-xml :nth-child(...) stores cache data on `parent`
1074 if ( forward && useCache ) {
1075 // Seek `elem` from a previously-cached index
1076 outerCache = parent[ expando ] || (parent[ expando ] = {});
1077 cache = outerCache[ type ] || [];
1078 nodeIndex = cache[0] === dirruns && cache[1];
1079 diff = cache[0] === dirruns && cache[2];
1080 node = nodeIndex && parent.childNodes[ nodeIndex ];
1081
1082 while ( (node = ++nodeIndex && node && node[ dir ] ||
1083
1084 // Fallback to seeking `elem` from the start
1085 //第一次執(zhí)行while循環(huán)時(shí)走這里(確切的說應(yīng)該是第一個(gè)遍歷childNodes節(jié)點(diǎn)時(shí))如果start內(nèi)沒有節(jié)點(diǎn)則循環(huán)一次找到節(jié)點(diǎn),這也是diff = nodeIndex = 0的原因
1086 (diff = nodeIndex = 0) || start.pop()) ) {
1087
1088 // When found, cache indexes on `parent` and break
1089 //當(dāng)獲取到的element,把這個(gè)element的索引值緩存在父節(jié)點(diǎn)[dirruns, 節(jié)點(diǎn)索引值, 真正的節(jié)點(diǎn)(不是文本或注釋節(jié)點(diǎn))]
1090 if ( node.nodeType === 1 && ++diff && node === elem ) {
1091 outerCache[ type ] = [ dirruns, nodeIndex, diff ];
1092 break;
1093 }
1094 }
1095
1096 // Use previously-cached element index if available
1097 } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
1098 diff = cache[1];
1099
1100 // 如果是xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
1101 } else {
1102 // Use the same loop as above to seek `elem` from the start
1103 while ( (node = ++nodeIndex && node && node[ dir ] ||
1104 (diff = nodeIndex = 0) || start.pop()) ) {
1105
1106 if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
1107 // Cache the index of each encountered element
1108 if ( useCache ) {
1109 (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
1110 }
1111
1112 if ( node === elem ) {
1113 break;
1114 }
1115 }
1116 }
1117 }
1118
1119 // Incorporate the offset, then check against cycle size
1120 diff -= last;
1121 return diff === first || ( diff % first === 0 && diff / first >= 0 );
1122 }
1123 };
1124 },
1125
1126 "PSEUDO": function( pseudo, argument ) {
1127
1128 //偽類names值不區(qū)分大小寫(不對(duì))
1129 //優(yōu)先大小寫敏感的定制偽類
1130 //setFilters繼承了pseudos
1131 var args,
1132 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
1133 Sizzle.error( "unsupported pseudo: " + pseudo );
1134 //上面的fn才是真正的篩選函數(shù)(有sizzle自己定義的,用戶也可以自定義)
1135
1136
1137 //用戶可能用createPseuso(需要?jiǎng)?chuàng)建一個(gè)過濾函數(shù)做為參數(shù))自定義一個(gè)偽類, 就像sizzle創(chuàng)建的一樣
1138 if ( fn[ expando ] ) {
1139 return fn( argument );
1140 }
1141
1142 //保持舊的簽名支持
1143 if ( fn.length > 1 ) {
1144 args = [ pseudo, pseudo, "", argument ];
1145 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
1146 markFunction(function( seed, matches ) {
1147 var idx,
1148 matched = fn( seed, argument ),
1149 i = matched.length;
1150 while ( i-- ) {
1151 idx = indexOf.call( seed, matched[i] );
1152 seed[ idx ] = !( matches[ idx ] = matched[i] );
1153 }
1154 }) :
1155 function( elem ) {
1156 return fn( elem, 0, args );
1157 };
1158 }
1159
1160 return fn;
1161 }
1162 },
1163
1164 pseudos: {
1165 // Potentially complex pseudos
1166 "not": markFunction(function( selector ) {
1167 // Trim the selector passed to compile
1168 // to avoid treating leading and trailing
1169 // spaces as combinators
1170 var input = [],
1171 results = [],
1172 matcher = compile( selector.replace( rtrim, "$1" ) );
1173
1174 return matcher[ expando ] ?
1175 markFunction(function( seed, matches, context, xml ) {
1176 var elem,
1177 unmatched = matcher( seed, null, xml, [] ),
1178 i = seed.length;
1179
1180 // Match elements unmatched by `matcher`
1181 while ( i-- ) {
1182 if ( (elem = unmatched[i]) ) {
1183 seed[i] = !(matches[i] = elem);
1184 }
1185 }
1186 }) :
1187 function( elem, context, xml ) {
1188 input[0] = elem;
1189 matcher( input, null, xml, results );
1190 return !results.pop();
1191 };
1192 }),
1193
1194 "has": markFunction(function( selector ) {
1195 return function( elem ) {
1196 return Sizzle( selector, elem ).length > 0;
1197 };
1198 }),
1199
1200 "contains": markFunction(function( text ) {
1201 return function( elem ) {
1202 return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
1203 };
1204 }),
1205
1206 // "Whether an element is represented by a :lang() selector
1207 // is based solely on the element's language value
1208 // being equal to the identifier C,
1209 // or beginning with the identifier C immediately followed by "-".
1210 // The matching of C against the element's language value is performed case-insensitively.
1211 // The identifier C does not have to be a valid language name."
1212 // http://www.w3.org/TR/selectors/#lang-pseudo
1213 "lang": markFunction( function( lang ) {
1214 // lang value must be a valid identifier
1215 if ( !ridentifier.test(lang || "") ) {
1216 Sizzle.error( "unsupported lang: " + lang );
1217 }
1218 lang = lang.replace( runescape, funescape ).toLowerCase();
1219 return function( elem ) {
1220 var elemLang;
1221 do {
1222 if ( (elemLang = documentIsHTML ?
1223 elem.lang :
1224 elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
1225
1226 elemLang = elemLang.toLowerCase();
1227 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
1228 }
1229 } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
1230 return false;
1231 };
1232 }),
1233
1234 // Miscellaneous
1235 "target": function( elem ) {
1236 var hash = window.location && window.location.hash;
1237 return hash && hash.slice( 1 ) === elem.id;
1238 },
1239
1240 "root": function( elem ) {
1241 return elem === docElem;
1242 },
1243
1244 "focus": function( elem ) {
1245 return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
1246 },
1247
1248 // Boolean properties
1249 "enabled": function( elem ) {
1250 return elem.disabled === false;
1251 },
1252
1253 "disabled": function( elem ) {
1254 return elem.disabled === true;
1255 },
1256
1257 "checked": function( elem ) {
1258 // In CSS3, :checked should return both checked and selected elements
1259 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
1260 var nodeName = elem.nodeName.toLowerCase();
1261 return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
1262 },
1263
1264 "selected": function( elem ) {
1265 // Accessing this property makes selected-by-default
1266 // options in Safari work properly
1267 if ( elem.parentNode ) {
1268 elem.parentNode.selectedIndex;
1269 }
1270
1271 return elem.selected === true;
1272 },
1273
1274 // Contents
1275 "empty": function( elem ) {
1276 // http://www.w3.org/TR/selectors/#empty-pseudo
1277 // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
1278 // not comment, processing instructions, or others
1279 // Thanks to Diego Perini for the nodeName shortcut
1280 // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
1281 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
1282 if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
1283 return false;
1284 }
1285 }
1286 return true;
1287 },
1288
1289 "parent": function( elem ) {
1290 return !Expr.pseudos["empty"]( elem );
1291 },
1292
1293 // Element/input types
1294 "header": function( elem ) {
1295 return rheader.test( elem.nodeName );
1296 },
1297
1298 "input": function( elem ) {
1299 return rinputs.test( elem.nodeName );
1300 },
1301
1302 "button": function( elem ) {
1303 var name = elem.nodeName.toLowerCase();
1304 return name === "input" && elem.type === "button" || name === "button";
1305 },
1306
1307 "text": function( elem ) {
1308 var attr;
1309 // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
1310 // use getAttribute instead to test this case
1311 return elem.nodeName.toLowerCase() === "input" &&
1312 elem.type === "text" &&
1313 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
1314 },
1315
1316 // Position-in-collection
1317 "first": createPositionalPseudo(function() {
1318 return [ 0 ];
1319 }),
1320
1321 "last": createPositionalPseudo(function( matchIndexes, length ) {
1322 return [ length - 1 ];
1323 }),
1324
1325 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
1326 return [ argument < 0 ? argument + length : argument ];
1327 }),
1328
1329 "even": createPositionalPseudo(function( matchIndexes, length ) {
1330 var i = 0;
1331 for ( ; i < length; i += 2 ) {
1332 matchIndexes.push( i );
1333 }
1334 return matchIndexes;
1335 }),
1336
1337 "odd": createPositionalPseudo(function( matchIndexes, length ) {
1338 var i = 1;
1339 for ( ; i < length; i += 2 ) {
1340 matchIndexes.push( i );
1341 }
1342 return matchIndexes;
1343 }),
1344
1345 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
1346 var i = argument < 0 ? argument + length : argument;
1347 for ( ; --i >= 0; ) {
1348 matchIndexes.push( i );
1349 }
1350 return matchIndexes;
1351 }),
1352
1353 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
1354 var i = argument < 0 ? argument + length : argument;
1355 for ( ; ++i < length; ) {
1356 matchIndexes.push( i );
1357 }
1358 return matchIndexes;
1359 })
1360 }
1361 };
1362
1363 //添加input和button偽類
1364 for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
1365 Expr.pseudos[ i ] = createInputPseudo( i );
1366 }
1367 for ( i in { submit: true, reset: true } ) {
1368 Expr.pseudos[ i ] = createButtonPseudo( i );
1369 }
1370
1371 //把selector解析成一個(gè)個(gè)獨(dú)立的塊
1372 function tokenize( selector, parseOnly ) {
1373 var matched, match, tokens, type,
1374 soFar, groups, preFilters,
1375 cached = tokenCache[ selector + " " ];
1376
1377 if ( cached ) {
1378 return parseOnly ? 0 : cached.slice( 0 );
1379 }
1380
1381 soFar = selector;
1382 groups = [];
1383 preFilters = Expr.preFilter;//正則出來的數(shù)組不能直接用需要過濾下如:attr正則出來的數(shù)組引號(hào)還有~=
1384
1385 while ( soFar ) {
1386
1387 //第一次運(yùn)行或者并聯(lián)選擇器逗號(hào)
1388 if ( !matched || (match = rcomma.exec( soFar )) ) {
1389 if ( match ) {
1390 // Don't consume trailing commas as valid
1391 soFar = soFar.slice( match[0].length ) || soFar;
1392 }
1393 groups.push( tokens = [] );
1394 }
1395
1396 matched = false;
1397
1398 //關(guān)系選擇器
1399 if ( (match = rcombinators.exec( soFar )) ) {
1400 matched = match.shift();
1401 tokens.push( {
1402 value: matched,
1403 type: match[0].replace( rtrim, " " )
1404 } );
1405 soFar = soFar.slice( matched.length );
1406 }
1407
1408 //過濾器
1409 for ( type in Expr.filter ) {
1410 //這里如果已匹配上是不是退出for等循環(huán)效率高點(diǎn)????tokenize函數(shù)要不要寫下(把rcomma、rcombinators、其它選擇器寫到一個(gè)for循環(huán))
1411 if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
1412 (match = preFilters[ type ]( match ))) ) {
1413 matched = match.shift();//真正的選擇器
1414 tokens.push( {
1415 value: matched,//真正的選擇器
1416 type: type,//選擇器類型
1417 matches: match//選擇器的各個(gè)部分如:attr ["[name="username"]", "name", "=", "username"]
1418 } );
1419 soFar = soFar.slice( matched.length );//截取當(dāng)前匹配的選擇器
1420 }
1421 }
1422
1423 if ( !matched ) {
1424 break;
1425 }
1426 }
1427
1428 //如果我們僅僅解析返回?zé)o效的長度,否則返回解析完的選擇器對(duì)象或者拋出錯(cuò)誤
1429 return parseOnly ?
1430 soFar.length :
1431 soFar ?
1432 Sizzle.error( selector ) :
1433 // Cache the tokens
1434 //緩存解析完的選擇器
1435 tokenCache( selector, groups ).slice( 0 );//拷貝緩存中的,因?yàn)槭且妙愋腿绻苯邮褂脮?huì)改變緩存中的值
1436 }
1437
1438 function toSelector( tokens ) {
1439 var i = 0,
1440 len = tokens.length,
1441 selector = "";
1442 for ( ; i < len; i++ ) {
1443 selector += tokens[i].value;
1444 }
1445 return selector;
1446 }
1447
1448 //根據(jù)關(guān)系選擇器檢查
1449 function addCombinator( matcher, combinator, base ) {
1450 var dir = combinator.dir,
1451 checkNonElements = base && dir === "parentNode",
1452 doneName = done++;//第幾個(gè)關(guān)系選擇器
1453 console.log('遇到第' + doneName + '個(gè)關(guān)系選擇器:');
1454 return combinator.first ?
1455 // Check against closest ancestor/preceding element
1456 //檢查最靠近的祖先元素
1457 function( elem, context, xml ) {
1458 while ( (elem = elem[ dir ]) ) {
1459 if ( elem.nodeType === 1 || checkNonElements ) {
1460 return matcher( elem, context, xml );
1461 }
1462 }
1463 } :
1464
1465 // Check against all ancestor/preceding elements
1466 //檢查最靠近的祖先元素或兄弟元素(概據(jù)>、~、+還有空格檢查)
1467 function( elem, context, xml ) {
1468 var data, cache, outerCache,
1469 dirkey = dirruns + " " + doneName;
1470
1471 //我們不可以在xml節(jié)點(diǎn)上設(shè)置任意數(shù)據(jù),所以它們不會(huì)從dir緩存中受益
1472 if ( xml ) {
1473 while ( (elem = elem[ dir ]) ) {
1474 if ( elem.nodeType === 1 || checkNonElements ) {
1475 if ( matcher( elem, context, xml ) ) {
1476 return true;
1477 }
1478 }
1479 }
1480 } else {
1481 while ( (elem = elem[ dir ]) ) {
1482 if ( elem.nodeType === 1 || checkNonElements ) {
1483 outerCache = elem[ expando ] || (elem[ expando ] = {});
1484 //如果有緩存且符合下列條件則不用再次調(diào)用matcher函數(shù)
1485 if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
1486 if ( (data = cache[1]) === true || data === cachedruns ) {
1487 return data === true;
1488 }
1489 } else {
1490 cache = outerCache[ dir ] = [ dirkey ];
1491 cache[1] = matcher( elem, context, xml ) || cachedruns;//cachedruns//正在匹配第幾個(gè)元素
1492 if ( cache[1] === true ) {
1493 return true;
1494 }
1495 }
1496 }
1497 }
1498 }
1499 };
1500 }
1501
1502 function elementMatcher( matchers ) {
1503 return matchers.length > 1 ?
1504 function( elem, context, xml ) {
1505 //這里代碼改為下面代碼方便調(diào)試
1506 // var i = matchers.length;
1507 // while ( i-- ) {
1508 // if ( !matchers[i]( elem, context, xml ) ) {
1509 // return false;
1510 // }
1511 // }
1512 var i = matchers.length;
1513 var matcher = null;
1514 while ( i-- ) {
1515 matcher = matchers[i];
1516 //console.log(matcher)
1517 if ( !matcher( elem, context, xml ) ) {
1518 return false;
1519 }
1520 }
1521 return true;
1522 } :
1523 matchers[0];
1524 }
1525
1526 function condense( unmatched, map, filter, context, xml ) {
1527 var elem,
1528 newUnmatched = [],
1529 i = 0,
1530 len = unmatched.length,
1531 mapped = map != null;
1532
1533 for ( ; i < len; i++ ) {
1534 if ( (elem = unmatched[i]) ) {
1535 if ( !filter || filter( elem, context, xml ) ) {
1536 newUnmatched.push( elem );
1537 if ( mapped ) {
1538 map.push( i );
1539 }
1540 }
1541 }
1542 }
1543
1544 return newUnmatched;
1545 }
1546
1547 //如:'\#test a input[name="username"]:last[type="text"] [value*=2]'(不建議寫這樣的選擇器)
1548 //preFilter位置偽類之前的所有選擇器過濾函數(shù) 如:'a input[name="username"]'選擇器的匹配函數(shù)
1549 //selector 位置偽類之前的所有選擇器 如:'a input[name="username"]'
1550 //matcher 位置偽類匹配函數(shù)
1551 //postFilter如果位置偽類后面還有選擇器, 且關(guān)系選擇器之前(如果有的話) 此選擇器的匹配函數(shù)
1552 //postFinder如果位置偽類后面還有關(guān)系選擇器,第一個(gè)關(guān)系選擇器以后的匹配函數(shù)
1553 //postSelector如果位置偽類后面還有關(guān)系選擇器,第一個(gè)關(guān)系選擇器以后的選擇器 如:' [value*=2]'
1554 function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
1555 if ( postFilter && !postFilter[ expando ] ) {
1556 postFilter = setMatcher( postFilter );
1557 }
1558 if ( postFinder && !postFinder[ expando ] ) {
1559 postFinder = setMatcher( postFinder, postSelector );
1560 }
1561 return markFunction(function( seed, results, context, xml ) {//得到位置偽類之前的選擇器的元素后在篩選出符合條件偽類選擇器的元素
1562 var temp, i, elem,
1563 preMap = [],
1564 postMap = [],
1565 preexisting = results.length,
1566
1567 //根據(jù)把位置偽類前面的選擇器查找出元素然后再篩選位置偽類和它后面的選擇器
1568 elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
1569
1570 // Prefilter to get matcher input, preserving a map for seed-results synchronization
1571 matcherIn = preFilter && ( seed || !selector ) ?
1572 condense( elems, preMap, preFilter, context, xml ) :
1573 elems,
1574
1575 matcherOut = matcher ?
1576 // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
1577 //如果postFinder存在,或者篩選的種子集存在,再或者篩選的種子集不存在但是postFilter存在或results中有值
1578 postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
1579
1580 // ...intermediate processing is necessary必須中間處理
1581 [] :
1582
1583 // ...otherwise use results directly否則立即用resluts
1584 results :
1585 matcherIn;
1586
1587 // Find primary matches
1588 if ( matcher ) {
1589 matcher( matcherIn, matcherOut, context, xml );
1590 }
1591
1592 // Apply postFilter
1593 if ( postFilter ) {
1594 temp = condense( matcherOut, postMap );
1595 postFilter( temp, [], context, xml );
1596
1597 // Un-match failing elements by moving them back to matcherIn
1598 //把沒有匹配失敗的元素放到matcherIn中
1599 i = temp.length;
1600 while ( i-- ) {
1601 if ( (elem = temp[i]) ) {
1602 matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
1603 }
1604 }
1605 }
1606
1607 if ( seed ) {
1608 if ( postFinder || preFilter ) {
1609 if ( postFinder ) {
1610 // Get the final matcherOut by condensing this intermediate into postFinder contexts
1611 temp = [];
1612 i = matcherOut.length;
1613 while ( i-- ) {
1614 if ( (elem = matcherOut[i]) ) {
1615 // Restore matcherIn since elem is not yet a final match
1616 temp.push( (matcherIn[i] = elem) );
1617 }
1618 }
1619 postFinder( null, (matcherOut = []), temp, xml );
1620 }
1621
1622 // Move matched elements from seed to results to keep them synchronized
1623 i = matcherOut.length;
1624 while ( i-- ) {
1625 if ( (elem = matcherOut[i]) &&
1626 (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
1627
1628 seed[temp] = !(results[temp] = elem);
1629 }
1630 }
1631 }
1632
1633 // Add elements to results, through postFinder if defined
1634 } else {
1635 matcherOut = condense(
1636 matcherOut === results ?
1637 matcherOut.splice( preexisting, matcherOut.length ) :
1638 matcherOut
1639 );
1640 if ( postFinder ) {
1641 postFinder( null, results, matcherOut, xml );
1642 } else {
1643 push.apply( results, matcherOut );
1644 }
1645 }
1646 });
1647 }
1648
1649 function matcherFromTokens( tokens ) {
1650 var checkContext, matcher, j,
1651 len = tokens.length,
1652 leadingRelative = Expr.relative[ tokens[0].type ],
1653 implicitRelative = leadingRelative || Expr.relative[" "],
1654 i = leadingRelative ? 1 : 0,
1655
1656 //確保這些元素可以在context中找到
1657 matchContext = addCombinator( function( elem ) {
1658 return elem === checkContext;
1659 }, implicitRelative, true ),
1660 matchAnyContext = addCombinator( function( elem ) {
1661 return indexOf.call( checkContext, elem ) > -1;
1662 }, implicitRelative, true ),
1663 //這里用來確定元素在哪個(gè)context
1664 matchers = [ function( elem, context, xml ) {
1665 return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
1666 (checkContext = context).nodeType ?
1667 matchContext( elem, context, xml ) :
1668 matchAnyContext( elem, context, xml ) );
1669 } ];
1670
1671 for ( ; i < len; i++ ) {
1672 if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
1673 //當(dāng)遇到關(guān)系選擇器時(shí)elementMatcher函數(shù)將matchers數(shù)組中的函數(shù)生成一個(gè)函數(shù)(elementMatcher利用了閉包所以matchers一直存在內(nèi)存中)
1674 matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
1675 } else {
1676 matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );//apply方式調(diào)用函數(shù), tokens[i].matches為參數(shù)
1677
1678 //返回一個(gè)特殊的位置匹配函數(shù)
1679 //偽類會(huì)把selector分兩部分
1680 if ( matcher[ expando ] ) {
1681 //發(fā)現(xiàn)下一個(gè)關(guān)系操作符(如果有話)并做適當(dāng)處理
1682 j = ++i;
1683 for ( ; j < len; j++ ) {
1684 if ( Expr.relative[ tokens[j].type ] ) {//如果位置偽類后面還有關(guān)系選擇器還需要篩選
1685 break;
1686 }
1687 }
1688 return setMatcher(
1689 i > 1 && elementMatcher( matchers ),
1690 i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, "$1" ),
1691 matcher,
1692 i < j && matcherFromTokens( tokens.slice( i, j ) ),//如果位置偽類后面還有選擇器需要篩選
1693 j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),//如果位置偽類后面還有關(guān)系選擇器還需要篩選
1694 j < len && toSelector( tokens )
1695 );
1696 }
1697 matchers.push( matcher );
1698 }
1699 }
1700
1701 return elementMatcher( matchers );
1702 }
1703
1704 function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
1705 // A counter to specify which element is currently being matched
1706 // 用計(jì)數(shù)器來指定當(dāng)前哪個(gè)元素正在匹配
1707 var matcherCachedRuns = 0,
1708 bySet = setMatchers.length > 0,
1709 byElement = elementMatchers.length > 0,
1710 superMatcher = function( seed, context, xml, results, expandContext ) {
1711 var elem, j, matcher,
1712 setMatched = [],
1713 matchedCount = 0,
1714 i = "0",
1715 unmatched = seed && [],
1716 outermost = expandContext != null,
1717 contextBackup = outermostContext,
1718 // We must always have either seed elements or context
1719 //我們必須總是檢查seed中的元素或context下的所有元素
1720 elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
1721 // Use integer dirruns iff this is the outermost matcher
1722 //用整數(shù)dirruns區(qū)分這個(gè)是最外層的匹配函數(shù)
1723 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
1724 if ( outermost ) {
1725 outermostContext = context !== document && context;
1726 cachedruns = matcherCachedRuns;
1727 }
1728
1729 //通過elementMatchers內(nèi)的所有匹配函數(shù)的元素立即添加到results中
1730 //保持變量i是一個(gè)字符串,如果一個(gè)元素也沒有下面的元素匹配數(shù)量matchedCount為'00'
1731 for ( ; (elem = elems[i]) != null; i++ ) {
1732 if ( byElement && elem ) {
1733 j = 0;
1734 while ( (matcher = elementMatchers[j++]) ) {
1735 if ( matcher( elem, context, xml ) ) {
1736 results.push( elem );
1737 break;
1738 }
1739 }
1740 if ( outermost ) {
1741 dirruns = dirrunsUnique;
1742 cachedruns = ++matcherCachedRuns;//正在匹配第幾個(gè)元素(同時(shí)告訴全局的,這里的全局是sizzle內(nèi)的不是window的)
1743 }
1744 }
1745
1746 // Track unmatched elements for set filters
1747 //跟蹤不匹配元素并設(shè)置過濾
1748 if ( bySet ) {
1749 // They will have gone through all possible matchers
1750 //它們已經(jīng)通過所有的匹配器,如果元素不匹配matchedCount減1
1751 if ( (elem = !matcher && elem) ) {
1752 matchedCount--;
1753 }
1754
1755 // Lengthen the array for every element, matched or not
1756 //如果seed中有元素的話,不管是否匹配都要把每個(gè)元素放到一個(gè)延長數(shù)組中
1757 if ( seed ) {
1758 unmatched.push( elem );
1759 }
1760 }
1761 }
1762
1763 // Apply set filters to unmatched elements
1764 //用設(shè)置的過濾器來去除不匹配的元素
1765 matchedCount += i;//i是所有元素?cái)?shù)量,matchedCount之前是不匹配的元素?cái)?shù)量,所以matchedCount += i就是匹配的數(shù)量
1766 if ( bySet && i !== matchedCount ) {
1767 j = 0;
1768 while ( (matcher = setMatchers[j++]) ) {
1769 //這里篩選unmatched內(nèi)的元素
1770 matcher( unmatched, setMatched, context, xml );//(這里的setMatched是引用類型,所以函數(shù)matcher內(nèi)給setMatched添加的元素和這里的setMatched一樣
1771 }
1772
1773 if ( seed ) {
1774 // Reintegrate element matches to eliminate the need for sorting
1775 if ( matchedCount > 0 ) {
1776 while ( i-- ) {
1777 if ( !(unmatched[i] || setMatched[i]) ) {
1778 setMatched[i] = pop.call( results );
1779 }
1780 }
1781 }
1782
1783 // Discard index placeholder values to get only actual matches
1784 setMatched = condense( setMatched );
1785 }
1786
1787 // Add matches to results
1788 //添加匹配元素到results
1789 push.apply( results, setMatched );
1790
1791 //并聯(lián)選擇器匹配成功后按規(guī)定排序
1792 if ( outermost && !seed && setMatched.length > 0 &&
1793 ( matchedCount + setMatchers.length ) > 1 ) {
1794
1795 Sizzle.uniqueSort( results );
1796 }
1797 }
1798
1799 // Override manipulation of globals by nested matchers
1800 if ( outermost ) {
1801 dirruns = dirrunsUnique;
1802 outermostContext = contextBackup;
1803 }
1804
1805 return unmatched;
1806 };
1807
1808 return bySet ?
1809 markFunction( superMatcher ) :
1810 superMatcher;
1811 }
1812
1813 compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
1814 var i,
1815 setMatchers = [],
1816 elementMatchers = [],
1817 cached = compilerCache[ selector + " " ];
1818
1819 if ( !cached ) {
1820 //生成一個(gè)遞歸函數(shù)用來檢查每個(gè)元素
1821 if ( !group ) {
1822 group = tokenize( selector );
1823 }
1824 i = group.length;
1825 while ( i-- ) {//如果是有并聯(lián)選擇器這里多次等循環(huán)
1826 cached = matcherFromTokens( group[i] );
1827 if ( cached[ expando ] ) {//說明有位置偽類選擇器
1828 setMatchers.push( cached );
1829 } else {
1830 elementMatchers.push( cached );
1831 }
1832 }
1833
1834 //當(dāng)是并聯(lián)選擇器時(shí)(也就是group數(shù)組有多個(gè)元素),elementMatchers和setMatchers可能都有值
1835 cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
1836 }
1837 return cached;
1838 };
1839
1840 function multipleContexts( selector, contexts, results ) {
1841 var i = 0,
1842 len = contexts.length;
1843 for ( ; i < len; i++ ) {
1844 Sizzle( selector, contexts[i], results );
1845 }
1846 return results;
1847 }
1848
1849 function select( selector, context, results, seed ) {
1850 var i, tokens, token, type, find,
1851 match = tokenize( selector );//把selector解析成一個(gè)個(gè)獨(dú)立的塊
1852
1853 if ( !seed ) {
1854 //如果不是并聯(lián)選擇器則盡量減少操作
1855 if ( match.length === 1 ) {
1856
1857 //如果第一個(gè)是selector是id我們可以設(shè)置context快速查找
1858 tokens = match[0] = match[0].slice( 0 );
1859 if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
1860 context.nodeType === 9 && documentIsHTML &&
1861 Expr.relative[ tokens[1].type ] ) {
1862
1863 context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
1864 if ( !context ) {//如果context這個(gè)元素(selector第一個(gè)id選擇器)都不存在就不用查找了
1865 return results;
1866 }
1867
1868 selector = selector.slice( tokens.shift().value.length );//去掉第一個(gè)id選擇器
1869 }
1870
1871 //如果selector中沒有有位置偽類從右向左匹配
1872 i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
1873 while ( i-- ) {
1874 token = tokens[i];
1875
1876 //如果遇到了關(guān)系選擇器中止
1877 if ( Expr.relative[ (type = token.type) ] ) {
1878 break;
1879 }
1880 if ( (find = Expr.find[ type ]) ) {
1881 //如果selector第一個(gè)選擇器是兄弟選擇器,則擴(kuò)大context范圍(原因要查找的節(jié)點(diǎn)在這里必須是它的父節(jié)點(diǎn)或祖先節(jié)點(diǎn))
1882 if ( (seed = find(
1883 token.matches[0].replace( runescape, funescape ),
1884 rsibling.test( tokens[0].type ) && context.parentNode || context
1885 )) ) {
1886
1887 //如果seed是空的或者tokens中沒有值了,就可以return了沒有必要查找了
1888 tokens.splice( i, 1 );
1889 selector = seed.length && toSelector( tokens );
1890 if ( !selector ) {
1891 push.apply( results, seed );
1892 return results;
1893 }
1894
1895 break;
1896 }
1897 }
1898 }
1899 }
1900 }
1901
1902 // Compile and execute a filtering function
1903 // Provide `match` to avoid retokenization if we modified the selector above
1904 //編譯并執(zhí)行過濾函數(shù)
1905 //上面如果修改了selector,match同樣修改,我們把match傳過去可以避免compile內(nèi)再次調(diào)用tokenize
1906 compile( selector, match )(
1907 seed,
1908 context,
1909 !documentIsHTML,
1910 results,
1911 rsibling.test( selector )//selector中是否有兄弟關(guān)系選擇器
1912 );
1913 return results;
1914 }
1915
1916 // Deprecated
1917 Expr.pseudos["nth"] = Expr.pseudos["eq"];
1918
1919 // Easy API for creating new setFilters
1920 //
1921 function setFilters() {}
1922
1923 setFilters.prototype = Expr.filters = Expr.pseudos;
1924 Expr.setFilters = new setFilters();
1925
1926 // Check sort stability
1927 support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
1928
1929 //初始化默認(rèn)document
1930 setDocument();
1931
1932 // Always assume the presence of duplicates if sort doesn't
1933 // pass them to our comparison function (as in Google Chrome).
1934 [0, 0].sort( sortOrder );
1935 support.detectDuplicates = hasDuplicate;
1936
1937 // EXPOSE
1938 //sizzle對(duì)外公開
1939 if ( typeof define === "function" && define.amd ) {
1940 define(function() { return Sizzle; });
1941 } else {
1942 window.Sizzle = Sizzle;
1943 }
1944 // EXPOSE
1945
1946 })( window );
部分參考:http://www.cnblogs.com/rubylouvre/archive/2013/03/05/2943666.html
轉(zhuǎn)載于:https://www.cnblogs.com/daycool/archive/2013/04/15/3023169.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的jquery--选择器sizzle源码分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js代码自动生成
- 下一篇: 第10章 部署Exchange2010