自己开始尝试读Sizzle源码。
 
1、Sizzle同过自执行函数的方式为自己创建了一个独立的作用域,它可以不依赖于jQuery的大环境而独立存在。因此它可以被应用到其它js库中。实现如下:(function(window, undefined){})(window, undefined);
 
2、Sizzle中最头疼的就是一大片的复杂正则表达式:
 
  // 为正则准备的字符串。匹配选择器中的布尔值,例如 $( "input:checked" );
  booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
  // 为正则准备的字符串。匹配所有空白符,包括空格、下一制表符、回车、换行
  whitespace = "[\\x20\\t\\r\\n\\f]",
  // 为正则准备的字符串。匹配unicode编码形式的字符串???
  characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
  
  matchExpr = {
    // 匹配ID
    "ID": new RegExp( "^#(" + characterEncoding + ")" ),
    // 匹配class
    "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
    // 匹配tag
    "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
    // 匹配attr
    "ATTR": new RegExp( "^" + attributes ),
    "PSEUDO": new RegExp( "^" + pseudos ),
    // 匹配child
    "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
      "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
      "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
    // 匹配boolean
    "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
    "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
      whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
  },
  // 匹配原生方法和属性
  rnative = /^[^{]+\{\s*\[native \w/,
  // 匹配id、tag、class,为简单选择器提供快速通道
  rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
  // 匹配input相关
  rinputs = /^(?:input|select|textarea|button)$/i,
 
3、看一下Sizzle的入口
// Sizzle的入口,但只处理简单选择器的情况或者浏览器提供了高级接口的情况
function Sizzle( selector, context, results, seed ) {
var match, elem, m, nodeType,
i, groups, old, nid, newContext, newSelector;
  // 如果用户传入context,则使用context的ownerDocument和document进行判断,否则使用默认值进行判断。如果是document,则调用setDocument方法
  if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
     // 该方法会根据不同的浏览器初始化不同的属性和方法。判断哪些属性时当前浏览器支持的。
setDocument( context );
}
  // 根据参数初始化context
context = context || document;
  // 最终需要返回的数据被存放在这里
results = results || [];
  // 如果没有传入selector,或者selector不是字符串,则直接返回result(这里不返回空数组时因为result可能有在参数中传入值)
if ( !selector || typeof selector !== "string" ) {
return results;
}
  // 如果context不是元素节点类型,并且也不是document节点类型,返回空数组。
if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
return [];
}
  // 如果是HTML文档(该参数在setDocument时被初始化),并且参数总传入的seed为空
if ( documentIsHTML && !seed ) {
    // 检测selector中是否有rquichExpr能够匹配到的字符串
if ( (match = rquickExpr.exec( selector )) ) {
// 如果匹配到ID(rquickExpr第一个捕获组中捕获的是ID)
if ( (m = match[1]) ) {
         // 如果selector是document类型
if ( nodeType === 9 ) {
            // 调用gEBI方法
elem = context.getElementById( m );
// 如果得到elem不为空,并且它存在父节点(如果不存在父节点,则可能是不存在于DOM树中的文档片段)
if ( elem && elem.parentNode ) {
// 因为调用gEBI在某些(哪些呢?)浏览器中得到属性name也是m的元素,所以需要过滤掉
if ( elem.id === m ) {
                // 将符合条件的元素push进results
results.push( elem );
return results;
}
} else {
return results;
}
} else {
// 如果context不是document节点,得到context所在的文档的document节点,并调用其gEBI方法
if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
              // 暂时还不知道contains做了什么
              contains( context, elem ) && elem.id === m ) {
results.push( elem );
return results;
}
} // 如果匹配到的是tag(rquickExpr第一个捕获组中捕获的是tag)
} else if ( match[2] ) {
         // 直接调用gEBTN方法得到结果并push到results中返回
push.apply( results, context.getElementsByTagName( selector ) );
return results; // 如果匹配到的是class(rquickExpr第一个捕获组中捕获的是class)并且该浏览器支持gEBCN方法,则调用gEBCN方法
} else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
         // 将结果push到results中返回
push.apply( results, context.getElementsByClassName( m ) );
return results;
}
} // 如果浏览器支持querySelectorAll方法
if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
nid = old = expando;
newContext = context;
newSelector = nodeType === 9 && selector; if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
groups = tokenize( selector ); if ( (old = context.getAttribute("id")) ) {
nid = old.replace( rescape, "\\$&" );
} else {
context.setAttribute( "id", nid );
}
nid = "[id='" + nid + "'] "; i = groups.length;
while ( i-- ) {
groups[i] = nid + toSelector( groups[i] );
}
newContext = rsibling.test( selector ) && context.parentNode || context;
newSelector = groups.join(",");
} if ( newSelector ) {
try {
push.apply( results,
newContext.querySelectorAll( newSelector )
);
return results;
} catch(qsaError) {
} finally {
if ( !old ) {
context.removeAttribute("id");
}
}
}
}
} // 其余的情况,交给select来处理
return select( selector.replace( rtrim, "$1" ), context, results, seed );
}

jQuery Sizzle选择器(二)的更多相关文章

  1. [转]JQuery - Sizzle选择器引擎原理分析

    原文: https://segmentfault.com/a/1190000003933990 ---------------------------------------------------- ...

  2. jQuery Sizzle选择器(一)

    1.浏览器对css选择器采取逆向(从右向左)解析的原因: 如果正向解析,例如「div div p em」,我们首先就要检查当前元素到 html 的整条路径,找到最上层的div,再往下找,如果遇到不匹配 ...

  3. jQuery Sizzle选择器(三)

    在Sizzle的入口方法Sizzle()中看到的一个根据浏览器来初始化document各个方法的函数setDocument(),接下来主要看一下这个方法都做了什么. 但之前有必要看一下它用到的一些Si ...

  4. jQuery笔记---选择器(二)

    1.选择器练习: 1)查找UL中的元素的内容 格式:$(“ul li:XX”).text() XX:代表方法 比如:获取到第一元素,然后获取当中的值 $(“ul li:first”).text() 获 ...

  5. jQuery基础学习(二)—jQuery选择器

    一.jQuery基本选择器 1.CSS选择器     在学习jQuery选择器之前,先介绍一下之前学过的CSS选择器. 选择器 语法 描述 示例   标签选择器 E {                 ...

  6. jQuery学习之二 jQuery选择器

    一.jQuery选择器是什么1.CSS选择器2.jQuery选择器 二.jQuery选择器的优势1.简洁的写法2.支持从CSS1到CSS3选择器3.完善的处理机制  传统js选择器假如要操作的元素不存 ...

  7. jQuery基本选择器模块(二)

    选择器模块 1.push方法的兼容性(了解) 问题:IE8不支持aplly方法中的第二个参数是 伪数组 目标:实现 push 方法的浏览器兼容性问题 var push = [].push; try { ...

  8. jQuery源码分析系列(三)Sizzle选择器引擎-下

    选择函数:select() 看到select()函数,if(match.length === 1){}存在的意义是尽量简化执行步骤,避免compile()函数的调用. 简化操作同样根据tokenize ...

  9. Sizzle选择器引擎介绍

    一.前言 Sizzle原来是jQuery里面的选择器引擎,后来逐渐独立出来,成为一个独立的模块,可以自由地引入到其他类库中.我曾经将其作为YUI3里面的一个module,用起来畅通无阻,没有任何障碍. ...

随机推荐

  1. yum更换国内源 yum下载rpm包 源码包安装

    7.6 yum更换国内源 7.7 yum下载rpm包 7.8/7.9 源码包安装 yum更换国内源 cd  /etc/yum.repo.d/ 删除源 rm -f   dvd.repo rm -f  C ...

  2. Lucene基础学习笔记

    在学校和老师一起做项目,在老师的推荐下深入学习了一些SqlServer的知识,看一些书下来哎也没记住多少,不过带来了新疑问. 不使用模糊查询,我应该用什么呢?如何能不影响数据库性能,还能做模糊查询呢? ...

  3. PCL(Point Cloud Library)的第三方库简单介绍(boost,eigen,flann,vtk,qhull)

    PCL由于融合了大量的第三方开源库,导致学习成本升高~在学习之前我们最好还是了解一下这些库都是干嘛的,以便有的放矢.在之后更好的使用 boost: C++的标准库的备用版,擅长从数学库到智能指针,从模 ...

  4. Single Pattern(单例模式)

    单例模式是一种常用的软件设计模式.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源.如果希望在系统中某个类的实例只能存在一个,单例模式是最好的 ...

  5. 一分钟理清Vue-cli 代码构建步骤。

    1. $ npm install vue -cli -g $ vue init webpack project-name $ cd project-name $ npm install $ npm r ...

  6. linux 测试网络延迟

    1.在A服务器上运行qperf  &作为服务器节点,由其他服务器来连接测试,默认监听tcp的19765端口.

  7. Android开发学习笔记-自定义控件的属性

    若想让自定义控件变得更加方便灵活,则就需要对控件进行定义属性,使其用起来更方便. 下面是自定义控件属性的方法 1.添加attrs.xml,内容格式样式可以参考sdk\platforms\android ...

  8. mysql触发器应用和创建表错误代码: 1118 Row size too large. 解决

    1.针对数据库查询问题的方便,可以建立重要表的log备份记录表,在主表的添加,修改,删除添加触发器,修改触发器增加触发字段的点,限制条件. 数据库log表查问题比从线上多台服务器上下载日志文件相对方便 ...

  9. Python爬虫-什么是爬虫?

    百度百科是这样定义爬虫的: 网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本.另外一些不常使用的名字还有蚂 ...

  10. Docker容器的生命周期管理

    https://blog.csdn.net/u010278923/article/details/78751306