jquery

来源:互联网 发布:2016年世界经济数据 编辑:程序博客网 时间:2024/05/19 23:12
   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",     //是否有nth1034                     forward = type.slice( -4 ) !== "last",//是否正向查找1035                     ofType = what === "of-type";     //是否有of-type1036 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如果后面还有元素返回false1059                                              //如果是of-type, name值全等返回false1060                                              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 index1076                                    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 start1085                                         //第一次执行while循环时走这里(确切的说应该是第一个遍历childNodes节点时)如果start内没有节点则循环一次找到节点,这也是diff = nodeIndex = 0的原因1086                                         (diff = nodeIndex = 0) || start.pop()) ) {1087 1088                                         // When found, cache indexes on `parent` and break1089                                         //当获取到的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 available1097                               } 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 start1103                                    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 element1108                                              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 size1120                               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继承了pseudos1131                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 pseudos1166           "not": markFunction(function( selector ) {1167                // Trim the selector passed to compile1168                // to avoid treating leading and trailing1169                // spaces as combinators1170                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() selector1207           // is based solely on the element's language value1208           // 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-pseudo1213           "lang": markFunction( function( lang ) {1214                // lang value must be a valid identifier1215                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           // Miscellaneous1235           "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 properties1249           "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 elements1259                // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked1260                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-default1266                // options in Safari work properly1267                if ( elem.parentNode ) {1268                     elem.parentNode.selectedIndex;1269                }1270 1271                return elem.selected === true;1272           },1273 1274           // Contents1275           "empty": function( elem ) {1276                // http://www.w3.org/TR/selectors/#empty-pseudo1277                // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),1278                //   not comment, processing instructions, or others1279                // Thanks to Diego Perini for the nodeName shortcut1280                //   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 types1294           "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 case1311                return elem.nodeName.toLowerCase() === "input" &&1312                     elem.type === "text" &&1313                     ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );1314           },1315 1316           // Position-in-collection1317           "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 valid1391                     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 tokens1434                //缓存解析完的选择器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 element1456           //检查最靠近的祖先元素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 elements1466           //检查最靠近的祖先元素或兄弟元素(概据>、~、+还有空格检查)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 synchronization1571                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否则立即用resluts1584                          results :1585                     matcherIn;1586 1587           // Find primary matches1588           if ( matcher ) {1589                matcher( matcherIn, matcherOut, context, xml );1590           }1591 1592           // Apply postFilter1593           if ( postFilter ) {1594                temp = condense( matcherOut, postMap );1595                postFilter( temp, [], context, xml );1596 1597                // Un-match failing elements by moving them back to matcherIn1598                //把没有匹配失败的元素放到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 contexts1611                          temp = [];1612                          i = matcherOut.length;1613                          while ( i-- ) {1614                               if ( (elem = matcherOut[i]) ) {1615                                    // Restore matcherIn since elem is not yet a final match1616                                    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 synchronized1623                     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 defined1634           } else {1635                matcherOut = condense(1636                     matcherOut === results ?1637                          matcherOut.splice( preexisting, matcherOut.length ) :1638                          matcherOut1639                );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           //这里用来确定元素在哪个context1664           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 matched1706      // 用计数器来指定当前哪个元素正在匹配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 context1719                     //我们必须总是检查seed中的元素或context下的所有元素1720                     elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),1721                     // Use integer dirruns iff this is the outermost matcher1722                     //用整数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 filters1747                     //跟踪不匹配元素并设置过滤1748                     if ( bySet ) {1749                          // They will have gone through all possible matchers1750                          //它们已经通过所有的匹配器,如果元素不匹配matchedCount减11751                          if ( (elem = !matcher && elem) ) {1752                               matchedCount--;1753                          }1754 1755                          // Lengthen the array for every element, matched or not1756                          //如果seed中有元素的话,不管是否匹配都要把每个元素放到一个延长数组中1757                          if ( seed ) {1758                               unmatched.push( elem );1759                          }1760                     }1761                }1762 1763                // Apply set filters to unmatched elements1764                //用设置的过滤器来去除不匹配的元素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 sorting1775                          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 matches1784                          setMatched = condense( setMatched );1785                     }1786 1787                     // Add matches to results1788                     //添加匹配元素到results1789                     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 matchers1800                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 || context1885                          )) ) {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 function1903      // Provide `match` to avoid retokenization if we modified the selector above1904      //编译并执行过滤函数1905      //上面如果修改了selector,match同样修改,我们把match传过去可以避免compile内再次调用tokenize1906      compile( selector, match )(1907           seed,1908           context,1909           !documentIsHTML,1910           results,1911           rsibling.test( selector )//selector中是否有兄弟关系选择器1912      );1913      return results;1914 }1915 1916 // Deprecated1917 Expr.pseudos["nth"] = Expr.pseudos["eq"];1918 1919 // Easy API for creating new setFilters1920 //1921 function setFilters() {}1922 1923 setFilters.prototype = Expr.filters = Expr.pseudos;1924 Expr.setFilters = new setFilters();1925 1926 // Check sort stability1927 support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;1928 1929 //初始化默认document1930 setDocument();1931 1932 // Always assume the presence of duplicates if sort doesn't1933 // pass them to our comparison function (as in Google Chrome).1934 [0, 0].sort( sortOrder );1935 support.detectDuplicates = hasDuplicate;1936 1937 // EXPOSE1938 //sizzle对外公开1939 if ( typeof define === "function" && define.amd ) {1940      define(function() { return Sizzle; });1941 } else {1942      window.Sizzle = Sizzle;1943 }1944 // EXPOSE1945 1946 })( window );

部分参考:http://www.cnblogs.com/rubylouvre/archive/2013/03/05/2943666.html


<script type="text/javascript"><!--google_ad_client = "ca-pub-1944176156128447";/* cnblogs 首页横幅 */google_ad_slot = "5419468456";google_ad_width = 728;google_ad_height = 90;//--></script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>