我们在经过词法分析,简单过滤,找到适合的种子集合之后,最终的选择器抽出了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在这里引入了编译函数的概念。
<!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); } function compile() { //种子合集 var seed = document.querySelectorAll('input') //选择器 var selector = "Aaron [name=ttt]"; var elementMatchers = []; var results = [] var match = [{ matches: ["div"], type: "TAG", value: "Aaron" }, { type: " ", value: " " }, { matches: ["name", "=", "ttt"], type: "ATTR", value: "[name=ttt]" }] elementMatchers.push(matcherFromTokens(match)); 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; } } results[0].checked = 'checked' } $('#test1').click(function() { compile(); }) </script> </body> </html>