在Sizzle函数中,若是能快速处理或者经过querySelector处理,那么就使用它处理。不然使用select函数处理 。javascript
select = Sizzle.select = function (selector, context, results, seed) { var i, tokens, token, type, find, // 断定是不是 pre-compiled 的选择器 compiled = typeof selector === "function" && selector, // 这里因为compiled 是false ,因此先认为selector 是字符串,进入tokenize函数 ,进入词法分析 。 // 将 selector 分为组并返回 match = !seed && tokenize((selector = compiled.selector || selector)); };
因此,这一节的主要内容是 tokenize 函数css
tokenize = Sizzle.tokenize = function (selector, parseOnly) { var matched, match, tokens, type, soFar, groups, preFilters, // 先查看是否有缓存 cached = tokenCache[selector + " "]; if (cached) { // 若是有缓存,就先从缓冲中取 。 return parseOnly ? 0 : cached.slice(0); } soFar = selector; // 下面对选择器从左至右进行分析 groups = []; // 用 , 分割的组合选择器,每一个选择器都是一个组 。 preFilters = Expr.preFilter; // 过滤器 while (soFar) { // 第一个运行matched 为undefined,必定为假 。 // 105行,找出逗号 rcomma = new RegExp("^" + whitespace + "*," + whitespace + "*"), // 逗号用来分组,因此下面if 的逻辑主要是添加组 ,即group 。 if (!matched || (match = rcomma.exec(soFar))) { if (match) { soFar = soFar.slice(match[0].length) || soFar; } // 将一个数组push到组中 。 groups.push((tokens = [])); } matched = false; // 106 行 rcombinators = new RegExp("^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*"), // 这个正则表达式就是为了找出 关系符 ">+~ " 。 // 在上面添加了组,把逗号已经去掉,下面就是逗号以后的标识符 ,首先 match = rcombinators.exec(soFar)) 断定关系符号,可是第一次从组跳下,这里确定为false 。因此又跳转到以后的if 。 if ((match = rcombinators.exec(soFar))) { matched = match.shift(); tokens.push({ value: matched, // Cast descendant combinators to space type: match[0].replace(rtrim, " ") }); soFar = soFar.slice(matched.length); } // 这里主要断定表示符是 id ,class 仍是 tag 。 // identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", 这里的 \\\\. 表示 在css中,能够有转义字符做为标识符 。好比 \$,\& // 捕捉属性选择器,这个正则是最难的,不必定彻底理解。 // attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + //"*([*^$|!~]?=)" + whitespace + //"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + //"*\\]", // booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", // 处理各类伪类 。 // pseudos = ":(" + identifier + ")(?:\\((" + //"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + //"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + //".*" + //")\\)|)", // matchExpr = { // "ID": new RegExp("^#(" + identifier + ")"), // "CLASS": new RegExp("^\\.(" + identifier + ")"), // "TAG": new RegExp("^(" + identifier + "|[*])"), // "ATTR": new RegExp("^" + attributes), // "PSEUDO": new RegExp("^" + pseudos), // "CHILD": new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + // "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + // "*(\\d+)|))" + whitespace + "*\\)|)", "i"), // "bool": new RegExp("^(?:" + booleans + ")$", "i"), // "needsContext": new RegExp("^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + // whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i") // }, for (type in Expr.filter) { // 若是是上面的一种 、 // preFilters是用于分析选择器的名字与参数 // 预处理,有的选择器,好比属性选择器与伪类从选择器组分割出来,还要再细分 // 属性选择器要切成属性名,属性值,操做符;伪类要切为类型与传参; // 子元素过滤伪类还要根据an+b的形式再划分 if ((match = matchExpr[type].exec(soFar)) && (!preFilters[type] || (match = preFilters[type](match)))) { matched = match.shift(); tokens.push({ value: matched, type: type, matches: match }); soFar = soFar.slice(matched.length); } } if (!matched) { break; } } // 正常状况下,soFar所有解析完毕,此时为空字符串 。若是仅仅如parse,那么返回剩下长度,不然,抛出异常 。 return parseOnly ? soFar.length : soFar ? Sizzle.error(selector) : // 缓存起来 。 tokenCache(selector, groups).slice(0); };
// 这是filter,返回match的柯里化函数 。在编译部分会使用,这里不会用到 。 filter: { // 标签过滤器 ,返回一个柯里化函数 。 // 验证元素的名称是否就是当前传入的Tag 。Tag放入闭包中 。 "TAG": function (nodeNameSelector) { var nodeName = nodeNameSelector.replace(runescape, funescape).toLowerCase(); return nodeNameSelector === "*" ? function () { return true; } : function (elem) { return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; }; }, // 类过滤器 ,返回一个柯里化函数 。 // 验证元素的类名称是否包含当前传入的className 。 "CLASS": function (className) { var pattern = classCache[className + " "]; return pattern || (pattern = new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)")) && classCache(className, function (elem) { return pattern.test(typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || ""); }); }, "ATTR": function (name, operator, check) { // 返回的是函数 ! return function (elem) { var result = Sizzle.attr(elem, name); // 若是属性值为空 if (result == null) { return operator === "!="; } // 若是操做符为空, if (!operator) { return true; } // 将属性值转化为字符串。 result += ""; return operator === "=" ? result === check : operator === "!=" ? result !== check : operator === "^=" ? check && result.indexOf(check) === 0 : operator === "*=" ? check && result.indexOf(check) > -1 : operator === "$=" ? check && result.slice(-check.length) === check : operator === "~=" ? (" " + result.replace(rwhitespace, " ") + " ").indexOf(check) > -1 : operator === "|=" ? result === check || result.slice(0, check.length + 1) === check + "-" : false; }; }, // 这里处理子元素过滤伪类,如:nth-child, :first-child, :only-child "CHILD": function (type, what, argument, first, last) { var simple = type.slice(0, 3) !== "nth", forward = type.slice(-4) !== "last", ofType = what === "of-type"; return first === 1 && last === 0 ? // Shortcut for :nth-*(n) function (elem) { return !!elem.parentNode; } : function (elem, context, xml) { var cache, outerCache, node, diff, nodeIndex, start, dir = simple !== forward ? "nextSibling" : "previousSibling", parent = elem.parentNode, name = ofType && elem.nodeName.toLowerCase(), useCache = !xml && !ofType; if (parent) { // :(first|last|only)-(child|of-type) if (simple) { while (dir) { node = elem; while ((node = node[dir])) { if (ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1) { return false; } } // Reverse direction for :only-* (if we haven't yet done so) start = dir = type === "only" && !start && "nextSibling"; } return true; } start = [forward ? parent.firstChild : parent.lastChild]; // non-xml :nth-child(...) stores cache data on `parent` if (forward && useCache) { // Seek `elem` from a previously-cached index outerCache = parent[expando] || (parent[expando] = {}); cache = outerCache[type] || []; nodeIndex = cache[0] === dirruns && cache[1]; diff = cache[0] === dirruns && cache[2]; node = nodeIndex && parent.childNodes[nodeIndex]; while ((node = ++nodeIndex && node && node[dir] || // Fallback to seeking `elem` from the start (diff = nodeIndex = 0) || start.pop())) { // When found, cache indexes on `parent` and break if (node.nodeType === 1 && ++diff && node === elem) { outerCache[type] = [dirruns, nodeIndex, diff]; break; } } // Use previously-cached element index if available } else if (useCache && (cache = (elem[expando] || (elem[expando] = {}))[type]) && cache[0] === dirruns) { diff = cache[1]; // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) } else { // Use the same loop as above to seek `elem` from the start while ((node = ++nodeIndex && node && node[dir] || (diff = nodeIndex = 0) || start.pop())) { if ((ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1) && ++diff) { // Cache the index of each encountered element if (useCache) { (node[expando] || (node[expando] = {}))[type] = [dirruns, diff]; } if (node === elem) { break; } } } } // Incorporate the offset, then check against cycle size diff -= last; return diff === first || (diff % first === 0 && diff / first >= 0); } }; }, "PSEUDO": function (pseudo, argument) { // pseudo-class names are case-insensitive // http://www.w3.org/TR/selectors/#pseudo-classes // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters // Remember that setFilters inherits from pseudos var args, fn = Expr.pseudos[pseudo] || Expr.setFilters[pseudo.toLowerCase()] || Sizzle.error("unsupported pseudo: " + pseudo); // The user may use createPseudo to indicate that // arguments are needed to create the filter function // just as Sizzle does if (fn[expando]) { return fn(argument); } // But maintain support for old signatures if (fn.length > 1) { args = [pseudo, pseudo, "", argument]; return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase()) ? markFunction(function (seed, matches) { var idx, matched = fn(seed, argument), i = matched.length; while (i--) { idx = indexOf(seed, matched[i]); seed[idx] = !(matches[idx] = matched[i]); } }) : function (elem) { return fn(elem, 0, args); }; } return fn; } },
preFilter: { "ATTR": function (match) { match[1] = match[1].replace(runescape, funescape); // Move the given value to match[3] whether quoted or unquoted match[3] = (match[3] || match[4] || match[5] || "").replace(runescape, funescape); if (match[2] === "~=") { match[3] = " " + match[3] + " "; } return match.slice(0, 4); }, "CHILD": function (match) { /* matches from matchExpr["CHILD"] 1 type (only|nth|...) 2 what (child|of-type) 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) 4 xn-component of xn+y argument ([+-]?\d*n|) 5 sign of xn-component 6 x of xn-component 7 sign of y-component 8 y of y-component */ //将它的伪类名称与传参拆分为更细的单元,以数组形式返回 //好比 ":nth-child(even)"变为 //["nth","child","even", 2, 0, undefined, undefined, undefined] match[1] = match[1].toLowerCase(); if (match[1].slice(0, 3) === "nth") { // nth-* requires argument if (!match[3]) { Sizzle.error(match[0]); } // numeric x and y parameters for Expr.filter.CHILD // remember that false/true cast respectively to 0/1 match[4] = +(match[4] ? match[5] + (match[6] || 1) : 2 * (match[3] === "even" || match[3] === "odd")); match[5] = +((match[7] + match[8]) || match[3] === "odd"); // other types prohibit arguments } else if (match[3]) { Sizzle.error(match[0]); } return match; }, "PSEUDO": function (match) { //将它的伪类名称与传参进行再处理 //好比:contains伪类会去掉两边的引号,反义伪类括号部分会再次提取 var excess, unquoted = !match[6] && match[2]; if (matchExpr["CHILD"].test(match[0])) { return null; } // Accept quoted arguments as-is if (match[3]) { match[2] = match[4] || match[5] || ""; // Strip excess characters from unquoted arguments } else if (unquoted && rpseudo.test(unquoted) && // Get excess from tokenize (recursively) (excess = tokenize(unquoted, true)) && // advance to the next closing parenthesis (excess = unquoted.indexOf(")", unquoted.length - excess) - unquoted.length)) { // excess is a negative index match[0] = match[0].slice(0, excess); match[2] = unquoted.slice(0, excess); } // Return only captures needed by the pseudo filter method (type and argument) return match.slice(0, 3); } },