通过Expr.find[ type ]我们找出选择器最右边的最终seed种子合集,通过Sizzle.compile函数编译器,我们把tokenize词法元素编译成闭包函数。
超级匹配superMatcher,用最佳的方式从seed种子集合筛选出需要的数据,也就是通过seed与compile的匹配,得出最终的结果。
superMatcher 函数
这个方法并不是一个直接定义的方法,通过matcherFromGroupMatchers( elementMatchers, setMatchers )方法return出来的一个curry化的函数,但是最后执行起重要作用的是它。
注意是compile()():
compile( selector, match )(
seed,
context,
!documentIsHTML,
results,
rsibling.test( selector ) && testContext( context.parentNode ) || context
);
superMatcher方法会根据参数seed 、expandContext和context确定一个起始的查询范围:
elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
有可能是直接从seed中查询过滤,也有可能在context或者context的父节点范围内。如果不是从seed开始,那只能把整个DOM树节点取出来过滤了,把整个DOM树节点取出来过滤了,它会先执行Expr.find["TAG"]( "*", outermost )这句代码等到一个elems集合(数组合集)。
context.getElementsByTagName( tag );
可以看出对于优化选择器,最右边应该写一个作用域的搜索范围context比较好。
开始遍历这个seed种子合集了:
while ( (matcher = elementMatchers[j++]) ) {
if ( matcher( elem, context, xml ) ) {
results.push( elem );
break;
}
}
elementMatchers:就是通过分解词法器生成的闭包函数了,也就是“终极匹配器”。
为什么是while?
前面就提到了,tokenize选择器是可以用过 “,”逗号分组 group,所以就会有个合集的概念了,matcher就得到了每一个终极匹配器。
通过代码很能看出来matcher方法运行的结果都是bool值,对里面的元素逐个使用预先生成的matcher方法做匹配,如果结果为true的则直接将元素堆入返回结果集。
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script src="http://code.jquery.com/jquery-latest.js"></script> <title></title> </head> <body> <button id="test1">超级匹配器,点击选中checked</button> <div id="text"> <div class="Aaron"> <input type="checkbox" name="readme" /> <input type="checkbox" name="ttt" /> <input type="checkbox" name="aaa" /> <p>Sizzle</p> </div> </div> <script type="text/javascript"> var filter = { ATTR: function(name, operator,check) { return function(elem) { var attr = elem.getAttribute(name) if (operator === "=") { if(attr === check){ return true } } return false; } }, TAG: function(nodeNameSelector) { return function(elem) { return elem.nodeName && elem.nodeName.toLowerCase() === nodeNameSelector; }; } } function addCombinator(matcher) { return function(elem, context, xml) { while ((elem = elem['parentNode'])) { if (elem.nodeType === 1) { //找到第一个亲密的节点,立马就用终极匹配器判断这个节点是否符合前面的规则 return matcher(elem); } } } } function elementMatcher(matchers) { return matchers.length > 1 ? function(elem, context, xml) { var i = matchers.length; while (i--) { if (!matchers[i](elem, context, xml)) { return false; } } return true; } : //单个匹配器的话就返回自己即可 matchers[0]; } function matcherFromTokens(tokens){ var len = tokens.length; var matcher, matchers = []; for (i = 0; i < len; i++) { if (tokens[i].type === " ") { matchers = [addCombinator(elementMatcher(matchers), matcher)]; } else { matcher = filter[tokens[i].type].apply(null, tokens[i].matches); matchers.push(matcher); } } return elementMatcher(matchers); } /** * 超级匹配器 * @return {[type]} [description] */ function matcherFromGroupMatchers(elementMatchers) { var superMatcher = function(seed) { var results = []; var matcher, elem; for (var i = 0; i < seed.length; i++) { matcher = elementMatchers[0]; var elem = seed[i]; if (matcher(elem)) { results.push(elem); break; } } return results; }; return superMatcher; } function compile() { //种子合集 var seed = document.querySelectorAll('input') //选择器 var selector = "Aaron [name=ttt]"; var elementMatchers = []; var match = [{ matches: ["div"], type: "TAG", value: "Aaron" }, { type: " ", value: " " }, { matches: ["name", "=", "ttt"], type: "ATTR", value: "[name=ttt]" }] elementMatchers.push(matcherFromTokens(match)); //超级匹配器 var cached = matcherFromGroupMatchers(elementMatchers) results = cached(seed) results[0].checked = 'checked' } $('#test1').click(function() { compile(); }) </script> </body> </html>