7-10 Sizzle编译原理(中)
本节编程练习不计算学习进度,请电脑登录imooc.com操作

Sizzle编译原理(中)

我们在经过词法分析,简单过滤,找到适合的种子集合之后,最终的选择器抽出了input这个种子合集seed,重组的选择器selectorAaron [name=ttt],还有词法分析合集group,通过tokenize最终分类出来的group分别都有对应的几种 type:

var match = [{
        matches: ["div"],
        type: "TAG",
        value: "Aaron"
}, {
        type: " ",
        value: " "
}, {
        matches: ["name", "=", "ttt"],
        type: "ATTR",
        value: "[name=ttt]"
}]

每一种type都会有对应的处理方法 Expr.filter:

Expr.filter = {
    ATTR   : function (name, operator, check) {
    CHILD  : function (type, what, argument, first, last) {
    CLASS  : function (className) {
    ID     : function (id) {
    PSEUDO : function (pseudo, argument) {
    TAG    : function (nodeNameSelector) {
}

可以把“元”理解为“原子”,也就是最小的那个匹配器。

每条选择器规则最小的几个单元可以划分为:ATTR | CHILD | CLASS | ID | PSEUDO | TAG

在Sizzle里边有一些工厂方法用来生成对应的这些元匹配器,它就是Expr.filter。

举2个例子(ID类型的匹配器由Expr.filter["ID"]生成,应该是判断elem的id属性跟目标属性是否一致),到这里应该想到Sizzle其实是不是就是通过对selector做“分词”,打散之后再分别从Expr.filter 里面去找对应的方法来执行具体的查询或者过滤的操作?

答案基本是肯定的。

但是这样常规的做法逻辑上是OK的,但是效率如何?

所以Sizzle有更具体和巧妙的做法,Sizzle在这里引入了编译函数的概念。

任务

  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.  
  24. <script type="text/javascript">
  25.  
  26. var filter = {
  27. ATTR: function(name, operator,check) {
  28. return function(elem) {
  29. var attr = elem.getAttribute(name)
  30. if (operator === "=") {
  31. if(attr === check){
  32. return true
  33. }
  34. }
  35. return false;
  36. }
  37. },
  38. TAG: function(nodeNameSelector) {
  39. return function(elem) {
  40. return elem.nodeName && elem.nodeName.toLowerCase() === nodeNameSelector;
  41. };
  42. }
  43. }
  44.  
  45.  
  46. function addCombinator(matcher) {
  47. return function(elem, context, xml) {
  48. while ((elem = elem['parentNode'])) {
  49. if (elem.nodeType === 1) {
  50. //找到第一个亲密的节点,立马就用终极匹配器判断这个节点是否符合前面的规则
  51. return matcher(elem);
  52. }
  53. }
  54. }
  55. }
  56.  
  57.  
  58. function elementMatcher(matchers) {
  59. return matchers.length > 1 ?
  60. function(elem, context, xml) {
  61. var i = matchers.length;
  62. while (i--) {
  63. if (!matchers[i](elem, context, xml)) {
  64. return false;
  65. }
  66. }
  67. return true;
  68. } :
  69. //单个匹配器的话就返回自己即可
  70. matchers[0];
  71. }
  72.  
  73.  
  74.  
  75. function matcherFromTokens(tokens){
  76. var len = tokens.length;
  77. var matcher, matchers = [];
  78. for (i = 0; i < len; i++) {
  79. if (tokens[i].type === " ") {
  80. matchers = [addCombinator(elementMatcher(matchers), matcher)];
  81. } else {
  82. matcher = filter[tokens[i].type].apply(null, tokens[i].matches);
  83. matchers.push(matcher);
  84. }
  85. }
  86. return elementMatcher(matchers);
  87. }
  88.  
  89.  
  90. function compile() {
  91. //种子合集
  92. var seed = document.querySelectorAll('input')
  93. //选择器
  94. var selector = "Aaron [name=ttt]";
  95. var elementMatchers = [];
  96. var results = []
  97. var match = [{
  98. matches: ["div"],
  99. type: "TAG",
  100. value: "Aaron"
  101. }, {
  102. type: " ",
  103. value: " "
  104. }, {
  105. matches: ["name", "=", "ttt"],
  106. type: "ATTR",
  107. value: "[name=ttt]"
  108. }]
  109. elementMatchers.push(matcherFromTokens(match));
  110. var matcher, elem;
  111. for (var i = 0; i < seed.length; i++) {
  112. matcher = elementMatchers[0];
  113. var elem = seed[i];
  114. if (matcher(elem)) {
  115. results.push(elem);
  116. break;
  117. }
  118. }
  119.  
  120.  
  121. results[0].checked = 'checked'
  122. }
  123.  
  124.  
  125. $('#test1').click(function() {
  126. compile();
  127. })
  128.  
  129.  
  130.  
  131.  
  132.  
  133. </script>
  134.  
  135. </body>
  136. </html>
下一节