首页 > 代码库 > JQuery_2.1.0_日记 5.5 Sizzle选择器(三)

JQuery_2.1.0_日记 5.5 Sizzle选择器(三)

function Sizzle( selector, context, results, seed ) {
        var match, elem, m, nodeType,
               // QSA vars
              i, groups, old, nid, newContext, newSelector;

        if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
              setDocument( context );
       }

    //上下文为传入context或document
       context = context || document;
        //查询结果集
       results = results || [];
        //如果没传入选择器表达式或者传入的选择器表达器类型不是string
        if ( !selector || typeof selector !== "string" ) {
               //返回
               return results;
       }
        //如果上下文不是Element或Document
        //返回空结果集
        if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
               return [];
       }
       
        //文档是HTML并且没有传入候选集seed
        if ( documentIsHTML && !seed ) {

               // Shortcuts
               // 快速匹配最常用的单一id tag class
               //rquickExpr 捕获组1:id 捕获组2:tag 捕获组3:class
               if ( (match = rquickExpr.exec( selector )) ) {
                      // Speed-up: Sizzle("#ID")
                      //id 分支
                      if ( (m = match[1]) ) {
                            //context是document
                            if ( nodeType === 9 ) {
                                  elem = context.getElementById( m );
                                   // Check parentNode to catch when Blackberry 4.6 returns
                                   // nodes that are no longer in the document (jQuery #6963)
                                   if ( elem && elem.parentNode ) {
                                          // Handle the case where IE, Opera, and Webkit return items
                                          // by name instead of ID
                                          //看上面注释!
                                          if ( elem.id === m ) {
                                                results.push( elem );
                                                 return results;
                                         }
                                  } else {
                                          return results;
                                  }
                           } else {
                                   // Context is not a document
                                   //得到上下文所属document,然后调用document.getElementById,并判断得到的elem是否属于contains并且看看elem的id属性是否等于m
                                   if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
                                         contains( context, elem ) && elem.id === m ) {
                                         results.push( elem );
                                          return results;
                                  }
                           }

                      // Speed-up: Sizzle("TAG")
                      // tag分支
                     } else if ( match[2] ) {
                           push.apply( results, context.getElementsByTagName( selector ) );
                            return results;

                      // Speed-up: Sizzle(".CLASS")
                      // class分支
                     } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
                           push.apply( results, context.getElementsByClassName( m ) );
                            return results;
                     }
              }

               // QSA path
               // 支持querySelectorAll,rbuggyQSA怪癖检查
               if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
                     nid = old = expando;
                     newContext = context;
                      //newSelector的值为false或selector
                      //如果nodeType !== 9 返回false,其他返回selector
                     newSelector = nodeType === 9 && selector;

                      // qSA works strangely on Element-rooted queries
                      // We can work around this by specifying an extra ID on the root
                      // and working up from there (Thanks to Andrew Dupont for the technique)
                      // IE 8 doesn‘t work on object elements
                      //如果调通querySelectorAll的是Element会出现一些怪异的问题
                      //所以在媛selector的基础上方添加一个id的属性选择器
                      //例如媛selector:div a,修正后为[id=‘xx‘] div a
                      if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
                           groups = tokenize( selector );
                            //如果Element元素有id,则使用原来id
                            if ( (old = context.getAttribute("id" )) ) {
                                   //rescape = /‘|\\/g
                                  nid = old.replace( rescape, "\\$&" );
                            //没有id设置一个临时id,此id是expando属性
                           } else {
                                  context.setAttribute( "id", nid );
                           }
                           nid = "[id=‘" + nid + "‘] " ;
                           i = groups.length;
                            while ( i-- ) {
                                  groups[i] = nid + toSelector( groups[i] );
                           }
                           newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
                           newSelector = groups.join( ",");
                     }
                      //修正newSelector,调用querySelectorAll
                      if ( newSelector ) {
                            try {
                                  push.apply( results,
                                         newContext.querySelectorAll( newSelector )
                                  );
                                   return results;
                           } catch(qsaError) {
                           } finally {
                                   //如果用的时临时id
                                   //删除
                                   if ( !old ) {
                                         context.removeAttribute( "id");
                                  }
                           }
                     }
              }
       }

        // All others
        //原生方法不可用时,调用
        return select( selector.replace( rtrim, "$1" ), context, results, seed );
}