在Sizzle函数中,如果能快速处理或者通过querySelector处理,那么就使用它处理。否则使用select函数处理 。

select函数

  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 函数

tokenize 函数

  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 部分


// 这是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;
}
},

priFilter

    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);
}
},

Sizzle 源码分析 (二)的更多相关文章

  1. Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题

    4.2 Fresco客户端与服务端的交互(一) 解决Q1问题 从这篇博客开始,我们开始讨论客户端与服务端是如何交互的,这个交互的入口,我们从Q1问题入手(博客按照这样的问题入手,是因为当时我也是从这里 ...

  2. Sizzle源码分析 (一)

    Sizzle 源码分析 (一) 2.1 稳定 版本 Sizzle 选择器引擎博大精深,下面开始阅读它的源代码,并从中做出标记 .先从入口开始,之后慢慢切入 . 入口函数 Sizzle () 源码 19 ...

  3. 框架-springmvc源码分析(二)

    框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...

  4. Tomcat源码分析二:先看看Tomcat的整体架构

    Tomcat源码分析二:先看看Tomcat的整体架构 Tomcat架构图 我们先来看一张比较经典的Tomcat架构图: 从这张图中,我们可以看出Tomcat中含有Server.Service.Conn ...

  5. 十、Spring之BeanFactory源码分析(二)

    Spring之BeanFactory源码分析(二) 前言 在前面我们简单的分析了BeanFactory的结构,ListableBeanFactory,HierarchicalBeanFactory,A ...

  6. Vue源码分析(二) : Vue实例挂载

    Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...

  7. 多线程之美8一 AbstractQueuedSynchronizer源码分析<二>

    目录 AQS的源码分析 该篇主要分析AQS的ConditionObject,是AQS的内部类,实现等待通知机制. 1.条件队列 条件队列与AQS中的同步队列有所不同,结构图如下: 两者区别: 1.链表 ...

  8. Sizzle源码分析:一 设计思路

    一.前言 DOM选择器(Sizzle)是jQuery框架中非常重要的一部分,在H5还没有流行起来的时候,jQuery为我们提供了一个简洁,方便,高效的DOM操作模式,成为那个时代的经典.虽然现在Vue ...

  9. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

  10. spring源码分析(二)Aop

    创建日期:2016.08.19 修改日期:2016.08.20-2016.08.21 交流QQ:992591601 参考资料:<spring源码深度解析>.<spring技术内幕&g ...

随机推荐

  1. HR最喜欢问的问题_"你的职业规划是什么?"

    很多面试官都会问,“你的职业规划是什么?”这个问题往往会难倒很多求职者.今天我跟大家分享,求职者怎样回答,才能更给自己加分 1.对目前自己要从事的这个岗位有清晰的认识,比如这个主要的工作是做什么的,大 ...

  2. 破解Linux系统开机密码

    在我们使用Linux虚拟机的时候,经常会忘记自己设置的开机密码,无奈之下只有重新建一个虚拟机,然而新建往往会浪费掉我们很多时间,这时候,知道如何破解Linux系统密码就显得很重要了. 下面我们使用bo ...

  3. ASP.NET Web基本原理

    ASP.NET Web基本原理 浏览器与服务器之间的交互 浏览器向服务器发送HTTP请求,具体如下: 1.浏览器向服务器发送TCP包,要求服务器打开连接 TCP包首部32位,占20字节,格式如图一: ...

  4. caffe:使用C++来提取任意一张图片的特征(从内存读取数据)

    0x00 关于使用C++接口来提取特征,caffe官方提供了一个extract_features.cpp的例程,但是这个文件的输入是blob数据,即使输入层使用的是ImageData,也需要在depl ...

  5. Java数据类型(基本数据类型)学习

    Java数据类型(基本数据类型)学习 与其他语言一样,Java编程同样存在,比如int a,float b等.在学习变量之前我就必须先了解Java的数据类型啦. Java的数据类型包括基本数据类型和引 ...

  6. 进击 spring !!

    1.spring简介 Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的.框架的主要优势之一就是其分层架构,分层架构允许您选择使用某一个组件,同时为 J2EE 应用程序开发提供集成 ...

  7. LNMP源码编译安装

    思路:根据Linux系统以及公司网站系统的信息,选择合适的安装包进行安装 一.查看系统信息 # uname -a                        # 查看内核/操作系统/CPU信息 # ...

  8. jQuery中的选择器(下)

    这一篇主要写过滤选择器和表单选择器 在这里,我不再已表格形式说明(自己太懒了),主要以文字形式说明一下每个选择器的作用描述.  3.过滤选择器 过滤选择器主要是通过特定的过滤规则筛选出所需的DOM元素 ...

  9. HDU4704Sum 费马小定理+大数取模

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4704 题目大意: 看似复杂,其实就是求整数n的划分数,4=1+1+2和4=1+2+1是不同的.因而可 ...

  10. 最新合购网源码net.asp程序 彩票合买功能采用全新内核、全新架构,更小巧、功能更强、更快、更安全稳定

    合买代购功能 可购彩种:福彩3D.排列3.重庆时时彩.天津时时彩.广东11选5.11运夺金.江苏快3.广西快3.拥有上百种玩法,更多彩种即将开发完成,更多的彩种不断开发更新中... 选号投注:建立追号 ...