• 【jQuery源码】select方法


      1 /**
      2  * select方法是Sizzle选择器包的核心方法之一,其主要完成下列任务: 
      3  * 1、调用tokenize方法完成对选择器的解析 
      4  * 2、对于没有初始集合(即seed没有赋值)且是单一块选择器(即选择器字符串中没有逗号), 
      5  *    完成下列事项: 
      6  *    1) 对于首选择器是ID类型且context是document的,则直接获取对象替代传入的context对象 
      7  *    2) 若选择器是单一选择器,且是id、class、tag类型的,则直接获取并返回匹配的DOM元素 
      8  *    3) 获取最后一个id、class、tag类型选择器的匹配DOM元素赋值给初始集合(即seed变量) 
      9  * 3、通过调用compile方法获取“预编译”代码并执行,获取并返回匹配的DOM元素 
     10  *  
     11  * @param selector 已去掉头尾空白的选择器字符串 
     12  * @param context 执行匹配的最初的上下文(即DOM元素集合)。若context没有赋值,则取document。 
     13  * @param results 已匹配出的部分最终结果。若results没有赋值,则赋予空数组。 
     14  * @param seed 初始集合 
     15  */
     16 select = Sizzle.select = function( selector, context, results, seed ) {
     17     var i, tokens, token, type, find,
     18         compiled = typeof selector === "function" && selector,
     19         //在没有seed的时候,调用tokensize方法进行词法解析,结果放在match中
     20         //seed - 种子合集(搜索器搜到符合条件的标签),放入到这个初始集合seed中
     21         match = !seed && tokenize( (selector = compiled.selector || selector) );
     22 
     23     results = results || [];
     24 
     25     // Try to minimize operations if there is no seed and only one group
     26     //只有一组选择器,也就是选择器中没有逗号
     27     if ( match.length === 1 ) {
     28 
     29         // Take a shortcut and set the context if the root selector is an ID
     30         //创建一个新的集合赋给tokens,确保原有集合不被更改
     31         tokens = match[0] = match[0].slice( 0 );
     32         /* 
     33              * 若选择器是以id类型开始,且第二个是关系符(即+~>或空格), 
     34              * 则获取id所属对象作为context继续完成后续的匹配 
     35              *  
     36              * 此处的条件判断依次为: 
     37              * tokens.length > 2 :若tokens有两个以上的选择器 
     38              * (token = tokens[0]).type === "ID" :第一个选择器的类型为ID(即以#开头的), 
     39              * support.getById :支持getElementById函数 
     40              * context.nodeType === 9 :context对象是document 
     41              * documentIsHTML :当前处理的是HTML代码 
     42              * Expr.relative[tokens[1].type] :第二个tokens元素是一个关系(即+~>或空格) 
     43              * 在满足上面所有条件的情况下,执行if内的语句体 
     44         */  
     45         if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
     46                 support.getById && context.nodeType === 9 && documentIsHTML &&
     47                 Expr.relative[ tokens[1].type ] ) {
     48 
     49             //查找id为matches[1]的元素
     50             context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
     51             if ( !context ) {
     52                 return results;
     53 
     54             // Precompiled matchers will still verify ancestry, so step up a level
     55             } else if ( compiled ) {
     56                 context = context.parentNode;
     57             }
     58 
     59             //去掉selector中第一个选择器
     60             selector = selector.slice( tokens.shift().value.length );
     61         }
     62 
     63         // Fetch a seed set for right-to-left matching
     64         //其中: "needsContext"= new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\(" + whitespace + "*((?:-\d)?\d*)" + whitespace + "*\)|)(?=[^-]|$)", "i" )
     65         //即是表示如果没有一些结构伪类,这些是需要用另一种方式过滤,在之后文章再详细剖析。
     66         //那么就从最后一条规则开始,先找出seed集合
     67         i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
     68         while ( i-- ) {
     69             token = tokens[i];
     70 
     71             // Abort if we hit a combinator
     72             //如果遇到了关系选择器则终止循环,> + ~ 空
     73             if ( Expr.relative[ (type = token.type) ] ) {
     74                 break;
     75             }
     76             /*
     77                 先看看有没有搜索器find,搜索器就是浏览器一些原生的取DOM接口,简单的表述就是以下对象了
     78                 Expr.find = {
     79                     'ID'    : context.getElementById,
     80                     'CLASS' : context.getElementsByClassName,
     81                     'NAME'  : context.getElementsByName,
     82                     'TAG'   : context.getElementsByTagName
     83                 }
     84             */
     85             if ( (find = Expr.find[ type ]) ) {
     86                 // Search, expanding context for leading sibling combinators
     87                 // 尝试一下能否通过这个搜索器搜到符合条件的初始集合seed
     88                 if ( (seed = find(
     89                     token.matches[0].replace( runescape, funescape ),
     90                     rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
     91                 )) ) {
     92 
     93                     // If seed is empty or no tokens remain, we can return early
     94                     //删除这条标签
     95                     tokens.splice( i, 1 );
     96                     selector = seed.length && toSelector( tokens );
     97                     //若当前选择器是否为空,把seed推入results,返回结果
     98                     if ( !selector ) {
     99                         push.apply( results, seed );
    100                         return results;
    101                     }
    102                     //已经找到了符合条件的seed集合,此时前边还有其他规则,跳出去
    103                     break;
    104                 }
    105             }
    106         }
    107     }
    108 
    109     // Compile and execute a filtering function if one is not provided
    110     // Provide `match` to avoid retokenization if we modified the selector above
    111     ( compiled || compile( selector, match ) )(
    112         seed,
    113         context,
    114         !documentIsHTML,
    115         results,
    116         rsibling.test( selector ) && testContext( context.parentNode ) || context
    117     );
    118     return results;
    119 };
  • 相关阅读:
    栈与递归
    细说二叉树的删除操作
    二叉树
    链表队列
    数组队列
    链表栈
    c语言实现数组栈
    c语言实现双链表
    HDU 4557 非诚勿扰(Treap找后继)
    POJ 3481 Double Queue(Treap模板题)
  • 原文地址:https://www.cnblogs.com/shytong/p/5351656.html
Copyright © 2020-2023  润新知