jquery--选择器sizzle源码分析

   1 (function( window, undefined ) {
   2 
   3 var i,
   4      cachedruns,//正在匹配第几个元素
   5      Expr,     //Sizzle.selectors的快捷方式
   6      getText,//获取文本函数
   7      isXML,     //是否为xml
   8      compile,//编译函数
   9      outermostContext,
  10      recompare,
  11      sortInput,
  12 
  13      // Local document vars
  14      setDocument,
  15      document,//这里只是document是个普通的变量,需要setDocument函数赋值处理过的真正的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函数
  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,//第几个关系选择器匹配函数
  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      //如果数组原生不支持indexOf,我们自己定义。获取元素在数组中的位置
  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      //正则表达式
  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      // 去掉两端空白和字符串中的反斜杠(如果连续两个去掉一个)正则
  79      rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
  80      //并联选择器的正则
  81      rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
  82      //关系选择器正则
  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      //原生函数正则
 105      rnative = /^[^{]+\{\s*\[native code/,
 106 
 107      //仅仅单个id或tag、class选择器正则(用来快速解析并获取元素)
 108      rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
 109      //jQuery自定义的伪类,它们不是的CSS规范的一部分,使用它们查询不能充分利用原生DOM提供的querySelectorAll() 方法来提高性能。为了在现代浏览器上获得更佳的性能,请使用 .filter(":input")代替。
 110      rinputs = /^(?:input|select|textarea|button)$/i,
 111      //同上
 112      rheader = /^h\d$/i,
 113 
 114      rescape = /'|\\/g,
 115      //属性没带引号正则
 116      rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
 117 
 118      //css转义,配合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转换为数组,因为数组比集合效率高
 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 //测试是否是原生函数
 162 function isNative( fn ) {
 163      return rnative.test( fn + "" );
 164 }
 165 
 166 //创建缓存函数(缓存大小默认为50,可以自己设置)
 167 //这里利用了闭包(私有变量、变量一直保存在内存中)
 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 //标记函数供sizzle特殊用途
 183 function markFunction( fn ) {
 184      fn[ expando ] = true;
 185      return fn;
 186 }
 187 
 188 // 用于做各种特征检测,比如是否支持某个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主函数
 204 //selector css选择器, context上下文,results结果集,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用原生函数
 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 //根据当前的document设置document相关的变量(只设置一次)
 328 setDocument = Sizzle.setDocument = function( node ) {
 329      var doc = node ? node.ownerDocument || node : preferredDoc;
 330 
 331      //如果document已经设置了返回(这里document是个变量初始值是undefined)
 332      //不是文档对象返回
 333      //文档对象没有返回根节点时返回
 334      if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
 335           return document;
 336      }
 337 
 338      //给document变量设置真正的文档
 339      document = doc;
 340      docElem = doc.documentElement;
 341 
 342      documentIsHTML = !isXML( doc );
 343 
 344      //检查getElementsByTagName是否会返回注释节点,IE6-8会混杂注释节点
 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不可以发现第二个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是一个问题多的API
 379           //1 IE6-7下getElementsByName与getElementById都不区分元素的name与ID
 380           //2 IE的getElementsByName只对表单元素有效,无视拥有相同name值的span div元素
 381           //3 IE6-7下即使通过document.createElement创建一个表单元素,动态设置name与插入
 382           //  DOM树,getElementsByName无法找到此元素,innerHTML也不行。一定需要以
 383           //   document.createElement("<input name="aaa"/>")方式生成元素才行。
 384           //   同样的情况也发生在iframe上,IE6-7的iframe的name也需要这样同时生成。
 385           //4 name本来是一个property,但标准浏览器好像已经默认setAttribute("name","xxx")
 386           //  也能被getElementsByName获取到。
 387           //5 IE6-8通过innerHTML生成包含name属性的元素时,可能发生无法捕获的错误
 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节点和节点id是否匹配过滤函数
 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      //根据标签查找节点
 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      //如果支持根据name查找节点
 494      Expr.find["NAME"] = support.getByName && function( tag, context ) {
 495           if ( typeof context.getElementsByName !== strundefined ) {
 496                return context.getElementsByName( name );
 497           }
 498      };
 499 
 500      //如果支持根据class查找节点
 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放到数组中
 510 
 511      rbuggyQSA = [ ":focus" ];//支持的querySelectorAll放到数组中
 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树的节点
 566                support.disconnectedMatch = matches.call( div, "div" );
 567 
 568                //Gecko对于非法选择符不会抛错,而是返回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           //重复删除标记
 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上不存在这个方法
 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      //确保属性选择器有引号(querySelectorAll需要有引号)
 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中文档片段也是分离的节点(createElement('div')这样创建的节点有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      //除非我们知道我们可以检测到重复的,假设他们的存在
 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 // 兄弟节点排序
 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 //创建一个伪类的过滤函数,此方法是根据表单元素的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 //创建一个伪类的过滤函数,此方法是根据表单元素的type值或标签类型生成
 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 //用于创建位置伪类的过滤函数,它们是模拟从左向右的顺序进行选择,
 826 //匹配到它时的结果集的位置来挑选元素的
 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是数组索引值,matches数组中可能会出现undefinde值 如:var arr = []; arr[10] = 10;这里前9项会是undefined
 840                     }
 841                }
 842           });
 843      });
 844 }
 845 
 846 //工具函数用于获取给定节点的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: {//正则出来的数组不能直接用需要过滤下如:attr正则出来的数组引号还有~=
 897           "ATTR": function( match ) {
 898                match[1] = match[1].replace( runescape, funescape );
 899 
 900                //不管有没有引号都把value值移到match[3]
 901                //有引号["[name="username"]", "name", "=", """, "username", undefined]
 902                //无引号["[name=username]", "name", "=", undefined, undefined, "username"]
 903                match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
 904 
 905                if ( match[2] === "~=" ) {//匹配属性值必须有空格分隔(这个选择器测试属性值中的每个单词字符串,其中“word”是一个由空白分隔的字符串定义的)
 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                //当选择器中有nth时
 928                if ( match[1].slice( 0, 3 ) === "nth" ) {
 929                     // nth-* requires argument
 930                     //当选择器中有nth时小括号内没有值说明不是合法的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分别转换为1和0,  true和false参与运算时会自动转换为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                //如果小括号内有引号 如:[":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                //不知道什么伪类会走这里
 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: {//过滤函数(判断各节点是否符合条件)
 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时,
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                                         //第一次执行while循环时走这里(确切的说应该是第一个遍历childNodes节点时)如果start内没有节点则循环一次找到节点,这也是diff = nodeIndex = 0的原因
1086                                         (diff = nodeIndex = 0) || start.pop()) ) {
1087 
1088                                         // When found, cache indexes on `parent` and break
1089                                         //当获取到的element,把这个element的索引值缓存在父节点[dirruns, 节点索引值, 真正的节点(不是文本或注释节点)]
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值不区分大小写(不对)
1129                //优先大小写敏感的定制伪类
1130                //setFilters继承了pseudos
1131                var args,
1132                     fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
1133                          Sizzle.error( "unsupported pseudo: " + pseudo );
1134                //上面的fn才是真正的筛选函数(有sizzle自己定义的,用户也可以自定义)
1135               
1136               
1137                //用户可能用createPseuso(需要创建一个过滤函数做为参数)自定义一个伪类, 就像sizzle创建的一样
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解析成一个个独立的块
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;//正则出来的数组不能直接用需要过滤下如:attr正则出来的数组引号还有~=
1384 
1385      while ( soFar ) {
1386 
1387           //第一次运行或者并联选择器逗号
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           //关系选择器
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等循环效率高点????tokenize函数要不要写下(把rcomma、rcombinators、其它选择器写到一个for循环)
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//选择器的各个部分如:attr ["[name="username"]", "name", "=", "username"]
1418                     } );
1419                     soFar = soFar.slice( matched.length );//截取当前匹配的选择器
1420                }
1421           }
1422 
1423           if ( !matched ) {
1424                break;
1425           }
1426      }
1427 
1428      //如果我们仅仅解析返回无效的长度,否则返回解析完的选择器对象或者抛出错误
1429      return parseOnly ?
1430           soFar.length :
1431           soFar ?
1432                Sizzle.error( selector ) :
1433                // Cache the tokens
1434                //缓存解析完的选择器
1435                tokenCache( selector, groups ).slice( 0 );//拷贝缓存中的,因为是引用类型如果直接使用会改变缓存中的值
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 //根据关系选择器检查
1449 function addCombinator( matcher, combinator, base ) {
1450      var dir = combinator.dir,
1451           checkNonElements = base && dir === "parentNode",
1452           doneName = done++;//第几个关系选择器
1453 console.log('遇到第' + doneName + '个关系选择器:');
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           //检查最靠近的祖先元素或兄弟元素(概据>、~、+还有空格检查)
1467           function( elem, context, xml ) {
1468                var data, cache, outerCache,
1469                     dirkey = dirruns + " " + doneName;
1470 
1471                //我们不可以在xml节点上设置任意数据,所以它们不会从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                               //如果有缓存且符合下列条件则不用再次调用matcher函数
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//正在匹配第几个元素
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               //这里代码改为下面代码方便调试
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位置伪类之前的所有选择器过滤函数 如:'a input[name="username"]'选择器的匹配函数
1549 //selector 位置伪类之前的所有选择器 如:'a input[name="username"]'
1550 //matcher 位置伪类匹配函数
1551 //postFilter如果位置伪类后面还有选择器, 且关系选择器之前(如果有的话) 此选择器的匹配函数
1552 //postFinder如果位置伪类后面还有关系选择器,第一个关系选择器以后的匹配函数
1553 //postSelector如果位置伪类后面还有关系选择器,第一个关系选择器以后的选择器 如:' [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                //根据把位置伪类前面的选择器查找出元素然后再筛选位置伪类和它后面的选择器
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           //这里用来确定元素在哪个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                //当遇到关系选择器时elementMatcher函数将matchers数组中的函数生成一个函数(elementMatcher利用了闭包所以matchers一直存在内存中)
1674                matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
1675           } else {
1676                matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );//apply方式调用函数, tokens[i].matches为参数
1677 
1678                //返回一个特殊的位置匹配函数
1679                //伪类会把selector分两部分
1680                if ( matcher[ expando ] ) {
1681                     //发现下一个关系操作符(如果有话)并做适当处理
1682                     j = ++i;
1683                     for ( ; j < len; j++ ) {
1684                          if ( Expr.relative[ tokens[j].type ] ) {//如果位置伪类后面还有关系选择器还需要筛选
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 )) ),//如果位置伪类后面还有关系选择器还需要筛选
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      // 用计数器来指定当前哪个元素正在匹配
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                     //用整数dirruns区分这个是最外层的匹配函数
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内的所有匹配函数的元素立即添加到results中
1730                //保持变量i是一个字符串,如果一个元素也没有下面的元素匹配数量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;//正在匹配第几个元素(同时告诉全局的,这里的全局是sizzle内的不是window的)
1743                          }
1744                     }
1745 
1746                     // Track unmatched elements for set filters
1747                     //跟踪不匹配元素并设置过滤
1748                     if ( bySet ) {
1749                          // They will have gone through all possible matchers
1750                          //它们已经通过所有的匹配器,如果元素不匹配matchedCount减1
1751                          if ( (elem = !matcher && elem) ) {
1752                               matchedCount--;
1753                          }
1754 
1755                          // Lengthen the array for every element, matched or not
1756                          //如果seed中有元素的话,不管是否匹配都要把每个元素放到一个延长数组中
1757                          if ( seed ) {
1758                               unmatched.push( elem );
1759                          }
1760                     }
1761                }
1762 
1763                // Apply set filters to unmatched elements
1764                //用设置的过滤器来去除不匹配的元素
1765                matchedCount += i;//i是所有元素数量,matchedCount之前是不匹配的元素数量,所以matchedCount += i就是匹配的数量
1766                if ( bySet && i !== matchedCount ) {
1767                     j = 0;
1768                     while ( (matcher = setMatchers[j++]) ) {
1769                          //这里筛选unmatched内的元素
1770                          matcher( unmatched, setMatched, context, xml );//(这里的setMatched是引用类型,所以函数matcher内给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                     //并联选择器匹配成功后按规定排序
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           //生成一个递归函数用来检查每个元素
1821           if ( !group ) {
1822                group = tokenize( selector );
1823           }
1824           i = group.length;
1825         while ( i-- ) {//如果是有并联选择器这里多次等循环
1826                cached = matcherFromTokens( group[i] );
1827                if ( cached[ expando ] ) {//说明有位置伪类选择器
1828                     setMatchers.push( cached );
1829                } else {
1830                     elementMatchers.push( cached );
1831                }
1832           }
1833 
1834           //当是并联选择器时(也就是group数组有多个元素),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解析成一个个独立的块
1852 
1853      if ( !seed ) {
1854           //如果不是并联选择器则尽量减少操作
1855           if ( match.length === 1 ) {
1856 
1857                //如果第一个是selector是id我们可以设置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这个元素(selector第一个id选择器)都不存在就不用查找了
1865                          return results;
1866                     }
1867 
1868                     selector = selector.slice( tokens.shift().value.length );//去掉第一个id选择器
1869                }
1870 
1871                //如果selector中没有有位置伪类从右向左匹配
1872                i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
1873                while ( i-- ) {
1874                     token = tokens[i];
1875 
1876                     //如果遇到了关系选择器中止
1877                     if ( Expr.relative[ (type = token.type) ] ) {
1878                          break;
1879                     }
1880                     if ( (find = Expr.find[ type ]) ) {
1881                          //如果selector第一个选择器是兄弟选择器,则扩大context范围(原因要查找的节点在这里必须是它的父节点或祖先节点)
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      //编译并执行过滤函数
1905      //上面如果修改了selector,match同样修改,我们把match传过去可以避免compile内再次调用tokenize
1906      compile( selector, match )(
1907           seed,
1908           context,
1909           !documentIsHTML,
1910           results,
1911           rsibling.test( selector )//selector中是否有兄弟关系选择器
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 //初始化默认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对外公开
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

转载于:https://www.cnblogs.com/daycool/archive/2013/04/15/3023169.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值