7-12 Sizzle超级匹配器(上)
本节编程练习不计算学习进度,请电脑登录imooc.com操作

Sizzle超级匹配器(上)

通过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的则直接将元素堆入返回结果集。

任务

  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  5. <script src="http://code.jquery.com/jquery-latest.js"></script>
  6. <title></title>
  7. </head>
  8. <body>
  9.  
  10.  
  11. <button id="test1">超级匹配器,点击选中checked</button>
  12.  
  13. <div id="text">
  14. <div class="Aaron">
  15. <input type="checkbox" name="readme" />
  16. <input type="checkbox" name="ttt" />
  17. <input type="checkbox" name="aaa" />
  18. <p>Sizzle</p>
  19. </div>
  20. </div>
  21.  
  22.  
  23. <script type="text/javascript">
  24.  
  25. var filter = {
  26. ATTR: function(name, operator,check) {
  27. return function(elem) {
  28. var attr = elem.getAttribute(name)
  29. if (operator === "=") {
  30. if(attr === check){
  31. return true
  32. }
  33. }
  34. return false;
  35. }
  36. },
  37. TAG: function(nodeNameSelector) {
  38. return function(elem) {
  39. return elem.nodeName && elem.nodeName.toLowerCase() === nodeNameSelector;
  40. };
  41. }
  42. }
  43.  
  44.  
  45. function addCombinator(matcher) {
  46. return function(elem, context, xml) {
  47. while ((elem = elem['parentNode'])) {
  48. if (elem.nodeType === 1) {
  49. //找到第一个亲密的节点,立马就用终极匹配器判断这个节点是否符合前面的规则
  50. return matcher(elem);
  51. }
  52. }
  53. }
  54. }
  55.  
  56.  
  57. function elementMatcher(matchers) {
  58. return matchers.length > 1 ?
  59. function(elem, context, xml) {
  60. var i = matchers.length;
  61. while (i--) {
  62. if (!matchers[i](elem, context, xml)) {
  63. return false;
  64. }
  65. }
  66. return true;
  67. } :
  68. //单个匹配器的话就返回自己即可
  69. matchers[0];
  70. }
  71.  
  72.  
  73.  
  74. function matcherFromTokens(tokens){
  75. var len = tokens.length;
  76. var matcher, matchers = [];
  77. for (i = 0; i < len; i++) {
  78. if (tokens[i].type === " ") {
  79. matchers = [addCombinator(elementMatcher(matchers), matcher)];
  80. } else {
  81. matcher = filter[tokens[i].type].apply(null, tokens[i].matches);
  82. matchers.push(matcher);
  83. }
  84. }
  85. return elementMatcher(matchers);
  86. }
  87.  
  88.  
  89.  
  90. /**
  91. * 超级匹配器
  92. * @return {[type]} [description]
  93. */
  94. function matcherFromGroupMatchers(elementMatchers) {
  95. var superMatcher = function(seed) {
  96. var results = [];
  97. var matcher, elem;
  98. for (var i = 0; i < seed.length; i++) {
  99. matcher = elementMatchers[0];
  100. var elem = seed[i];
  101. if (matcher(elem)) {
  102. results.push(elem);
  103. break;
  104. }
  105. }
  106. return results;
  107. };
  108. return superMatcher;
  109. }
  110.  
  111.  
  112.  
  113.  
  114. function compile() {
  115. //种子合集
  116. var seed = document.querySelectorAll('input')
  117. //选择器
  118. var selector = "Aaron [name=ttt]";
  119. var elementMatchers = [];
  120. var match = [{
  121. matches: ["div"],
  122. type: "TAG",
  123. value: "Aaron"
  124. }, {
  125. type: " ",
  126. value: " "
  127. }, {
  128. matches: ["name", "=", "ttt"],
  129. type: "ATTR",
  130. value: "[name=ttt]"
  131. }]
  132.  
  133. elementMatchers.push(matcherFromTokens(match));
  134.  
  135.  
  136. //超级匹配器
  137. var cached = matcherFromGroupMatchers(elementMatchers)
  138. results = cached(seed)
  139.  
  140. results[0].checked = 'checked'
  141. }
  142.  
  143.  
  144. $('#test1').click(function() {
  145. compile();
  146. })
  147.  
  148.  
  149.  
  150.  
  151.  
  152. </script>
  153.  
  154. </body>
  155. </html>
下一节