【jQuery源码】tokenize方法

  1 //得到由选择器生成的token对象的数组(下面的groups)
  2 //Sizzle的Token格式如下 :{value:'匹配到的字符串', type:'对应的Token类型', matches:'正则匹配到的一个结构'}
  3 //比如"title,div > :nth-child(even)"解析下面的符号流
  4     // [ [{value:"title",type:"TAG",matches:["title"]}],
  5     //   [{value:"div",type:["TAG",matches:["div"]},
  6     //    {value:">", type: ">"},
  7     //    {value:":nth-child(even)",type:"CHILD",matches:["nth",
  8     //     "child","even",2,0,undefined,undefined,undefined]}
  9     //   ]
 10     // ]
 11     //有多少个并联选择器,里面就有多少个数组,数组里面是拥有value与type的对象
 12 
 13 //tokenize两个作用:1.解析选择器;2.将解析结果存入缓存
 14 tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
 15     var matched, match, tokens, type,
 16         soFar, groups, preFilters,
 17         cached = tokenCache[ selector + " " ];
 18     //这里的soFar是表示目前还未分析的字符串剩余部分
 19 
 20     //如果tokenCache中已经有selector了,则直接拿出来就好了
 21     if ( cached ) {
 22         return parseOnly ? 0 : cached.slice( 0 );
 23     }
 24 
 25     soFar = selector;
 26     groups = [];
 27 
 28     //这里的预处理器为了对匹配到的Token适当做一些调整
 29     preFilters = Expr.preFilter;
 30 
 31     //循环处理字符串
 32     while ( soFar ) {
 33 
 34         // Comma and first run
 35         //whitespace = "[\\x20\\t\\r\\n\\f]";
 36         //rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" );
 37         //!matched:若是第一次执行循环体,则为true;否则为false。 
 38         //这里matched即作为是否第一次执行循环体的标识,
 39         if ( !matched || (match = rcomma.exec( soFar )) ) {
 40             if ( match ) {
 41                 // Don't consume trailing commas as valid
 42                 //去掉sofar中第一个的无用",",比如",div,#id"中的第一个","
 43                 //举个例子,"div.news,span.closed"
 44                 //在解析过程中,首先由后续代码解析完毕div.news,剩下",span.closed"
 45                 //在循环体内执行到这里时,将逗号及之前之后连续的空白(match[0])删除掉, 
 46                 //使soFar变成"span.closed",继续执行解析过程
 47                 soFar = soFar.slice( match[0].length ) || soFar;
 48             }
 49             //往规则组里边压入一个Token序列,目前Token序列还是空的
 50             groups.push( (tokens = []) );
 51         }
 52 
 53         matched = false;
 54 
 55         // Combinators
 56         //rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*"), 
 57         //rcombinators用来匹配四种关系符,即>+~和空白
 58         if ( (match = rcombinators.exec( soFar )) ) {
 59             // 举个例子: 
 60             // 若soFar = " + .div"; 
 61             // 执行match = rcombinators.exec(soFar)后, 
 62             // match[0] = " + ",而match[1]="+"; 
 63             // 执行完matched = match.shift()后, 
 64             // matched=" + ",而match[0]="+"; 
 65             matched = match.shift();
 66             tokens.push({
 67                 value: matched,
 68                 // Cast descendant combinators to space
 69                 type: match[0].replace( rtrim, " " )
 70             });
 71             soFar = soFar.slice( matched.length );
 72         }
 73 
 74         // Filters
 75         //下面通过for语句对soFar逐一匹配ID、TAG、CLASS、CHILD、ATTR、PSEUDO类型的选择器 
 76         // 若匹配到了,则先调用该类型选择器对应的预过滤函数, 
 77         // 然后,将结果压入tokens数组,继续本次循环。
 78         for ( type in Expr.filter ) {
 79             //  match = matchExpr[type].exec(soFar):对soFar调用type类型的正则表达式对soFar进行匹配 
 80             // 并将匹配结果赋予match。若未匹配到数据,则match为null。 
 81             // !preFilters[type]:若不存在type类型的预过滤函数,则为true 
 82             // match = preFilters[type](match):执行预过滤,并将结果返回给match
 83             if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
 84                 (match = preFilters[ type ]( match ))) ) {
 85                 // 将match[0]移除match数组,同时将它赋予matched  
 86                 matched = match.shift();
 87                 // 将匹配结果压入tokens数组中
 88                 tokens.push({
 89                     value: matched,
 90                     type: type,
 91                     matches: match
 92                 });
 93                 // 将匹配结果之后的字符串赋予soFar,继续解析
 94                 soFar = soFar.slice( matched.length );
 95             }
 96         }
 97 
 98         //matched为false,说明本次循环没有效的选择器(包括关系符和id、class等类型选择器)
 99         if ( !matched ) {
100             break;
101         }
102     }
103 
104     // Return the length of the invalid excess
105     // if we're just parsing
106     // Otherwise, throw an error or return tokens
107     return parseOnly ?
108         soFar.length :
109         soFar ?
110             Sizzle.error( selector ) :
111             // Cache the tokens
112             tokenCache( selector, groups ).slice( 0 );
113 };

 

画一张直观图便于理解

image

posted @ 2016-03-30 11:04  很好玩  阅读(673)  评论(0编辑  收藏  举报