这篇博客难度太大,跟前端开发其实没什么关系,如果你想成为大牛,那就去了解下吧。如果你还不想,那可以忽略,毕竟面试官也不会问到这里来,因为他也不太懂。呵呵。

Sizzle引擎是jQuery的选择器,它大部分操作都是从右到左进行选择,特殊选择符会从左到右。用户输入$("div"),$("div p.class"),$("div [attr=val] :checked")等各种复杂的选择符,它都能选择到用户想要取到的元素节点。

Sizzle的整体结构如下:

(1)Sizzle主函数,里面包含选择符的切割,内部循环调用主查找函数,主过滤函数,最后是去重过滤。

(2)其他辅助函数,如 uniqueSort, matches ,matchesSelector。

(3)Sizzle.find主查找函数

(4)Sizzle.filter主过滤函数

(5)Sizzle.selectors 包含各种匹配用的正则,过滤用的正则,分解用的正则,预处理函数,过滤函数。

(6)根据浏览器的特征设计makeArray,sortOrder,contains等方法。

(7)根据浏览器的特征重写Sizzle.selectors中的部分查找函数,过滤函数,查找次序。

(8)若浏览器支持querySelectorAll,那么用它重写Sizzle,将原来的Sizzle作为后备方案包裹在新的Sizzle里面。

(9)其他辅助函数,如:isXML,posProcess。

Sizzle.find主查找函数和Sizzle.filter过滤函数实现原理:

对js原生的4大查找函数,getElementById(针对id),getElementsByName(针对name),getElementsByTagName(针对标签名tagName,比如div,p),getElementsByClassName(针对class),进行一层封装,浏览器支持的话,就返回数组或者NodeList,不支持的,就返回undefined。

这里需要讲一下种子集,

种子集就是通过最右边的选择器组得到的元素集合。比如:"div.aaa span.bbb",最右边的选择器组就是"span.bbb",这时引擎会根据浏览器的支持情况选择getElementsByTagName(span)或getElementsByClassName(bbb)得到一组元素,然后再通过class(bbb)或tagName(span)进行过滤,这时得到的集合就是种子集。种子集是分两步筛选出来的,首先,通过Sizzle.find得到一个大体的结果,然后通过Sizzle.filter过滤。那我们是先取span,还是.bbb呢?这里有一个准则,要确保我们后面的映射集(当我们取得种子集后,会将种子集复制一份,这就是映射集)最小。为了达到此目的,这里有一个优化,原生选择器的调用顺序被放在一个Sizzle.selectors.order的数组中,对于低版本浏览器,其顺序为id,name,tagName,对于支持getElementsByClassName的浏览器,顺序为id,class,name,tagName。因为id只返回一个元素,class与样式相关,不是每个元素都有这个类名的,name属性使用到的几率比较少,而tagName排除的元素比较少。所以Sizzle.find就会根据Sizzle.selectors.order数组,依次调用正则,从最右的选择器中切下需要的部分,找到粗糙的节点集合。(针对"span.bbb",id调用正则时,找不到,然后class,调用正则,找到.bbb,因此就调用getElementsByClassName(bbb)得到一组数据,最后通过Sizzle.filter过滤取到的数据,过滤条件是tagName(span))

映射集,

当我们取得种子集后,会将种子集复制一份,这就是映射集。种子集是由一个选择器组选出来的,这时如果选择符不为空(前面是"div.aaa"),必然往左就是关系选择器(父亲,兄弟,后代),关系选择器会让引擎去选取其兄长或父亲,把这些元素置换到映射集对等的位置上(个数不变,因此映射集和种子集的数量总是相当)。然后到下一个选择器组时("div.aaa"),就是过滤操作了。主过滤函数Sizzle.filter会调用Sizzle.selectors下的N个过滤函数对这些元素进行检测,将不符合的元素替换为false。因此到最后要去重排时,映射集是一个包含布尔值与元素节点的数组。

下面就是根据浏览器的特征进行优化:

IE6,7下getElementById有bug。需要重写。

IE6-IE8下,Array.prototype.slice.call无法切割NodeList。需要重写makeArray。jQuery中直接用循环,把类数组转化成数组。

IE6-IE8下,getElementsByTagName("*"),会混杂注释节点。

这里大家可能会提出现在有些浏览器支持querySelectorAll方法,这是原生的,可以用来选择元素。

在Sizzle中,当浏览器支持querySelectorAll方法时,会重写Sizzle。但是在重写时,会根据不同情况提出各种提速方案:

(1)getElementById还是比querySelectorAll速度快,因为getElementById只返回一个元素,而且内部做了缓存,但是querySelectorAll会返回拥有这个id值的多个元素,尽管页面id一般是唯一的,但如果出现了多个同样id的情况下,getElementById还是只返回一个元素,而querySelectorAll会返回多个。

(2)getElementsByTagName内部也使用了缓存,而且返回的是NodeList对象,querySelectorAll返回的是一个StaticNodeList对象,前面是动态的,后面是静态的。区别在于:document.getElementsByTagName("div") == document.getElementsByTagName("div"),返回真,document.querySelectorAll("div") == document.querySelectorAll("div"),返回false.返回true的,意味着它们拿到的同是cache引用。返回false意味着每次返回都是不一样的object。数据表明:创建一个动态的NodeList对象比创建一个静态的StaticNodeList对象快90%.

加油!

转载于:https://www.cnblogs.com/chaojidan/p/4140199.html

第十二课:Sizzle引擎详解相关推荐

  1. MySQL数据库,从入门到精通:第十二篇——MySQL数据类型详解

    MySQL数据库,从入门到精通:第十二篇--MySQL数据类型详解 第 12 章_MySQL数据类型精讲 1. MySQL中的数据类型 2. 整数类型 2. 1 类型介绍 2. 2 可选属性 2. 2 ...

  2. (十二)命令模式详解(故事版)- 转

    作者:zuoxiaolong8810(左潇龙),转载请注明出处. 背景:小左是魔都某公司技术部的一名屌丝程序猿,每天的工作就是维护一个20世纪的古董级项目,由于公司不大,所以公司很多制度不太完善,导致 ...

  3. (二十二)访问者模式详解(伪动态双分派) - 转

    作者:zuoxiaolong8810(左潇龙),转载请注明出处. 本次LZ和各位分享一下访问者模式,从场景.设计初衷以及实现方面来说,访问者模式算是LZ即将写到的24种设计模式当中,最复杂也是最难理解 ...

  4. 面渣逆袭:Redis连环五十二问,图文详解,这下面试稳了

    大家好,我是老三,面渣逆袭系列继续,这节我们来搞定Redis--不会有人假期玩去了吧?不会吧? 基础 1.说说什么是Redis? Redis是一种基于键值对(key-value)的NoSQL数据库. ...

  5. 【Android游戏开发二十二】(图文详解)游戏中灵活实现动画播放!简述J2me的游戏类库与Android游戏开发!

    本站文章均为 李华明Himi 原创,转载务必在明显处注明:(作者新浪微博: @李华明Himi ) 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/andr ...

  6. 零基础班第十五课 - Hive DDL详解

    第一章:上次课回顾 1.1 Hive部署过程中出现的坑 第二章:Hive DDL语句 2.1 图解Hive结构 2.2 创建数据库 2.2.1 数据库建表语句 2.2.2 数据库解析 2.2.3 修改 ...

  7. Javascript(十二)javascript 事件详解

    一.事件定义 关于事件实际上我们已经初步接触过了,指的就是用户与浏览器交互的一瞬间. 我们通过为指定事件绑定回调函数的形式来处理事 件,当指定事件触发以后我们的回调函数就会被调用,这样我们的页面就可以 ...

  8. NIO详解(十二):AsynchronousFileChannel详解

    1. 概述 Java NIO中的FileChannel是一个连接到文件的通道.可以通过文件通道读写文件.FileChannel无法设置为非阻塞模式,他总是运行在阻塞模式下.在Java 7中,Async ...

  9. (十二)命令模式详解(故事版)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处. 背景:小左是魔都某公司技术部的一名屌丝程序猿,每天的工作就是维护一个20世纪的古董级项目,由于公司不大,所以公司很多制度不太完善,导致 ...

最新文章

  1. 数据科学的积累:海平面下的冰山 | 清华信息技术研究院郑方
  2. python3入门教程-Python3 入门教程 简单但比较不错
  3. Watch out for these 10 common pitfalls of experienced Java developers architects--转
  4. 【PM模块】外包服务、工作清场管理、预防性维护
  5. 【Django】ORM操作#2
  6. 2012.2.18-silverlight设计器崩溃
  7. WCF部署到IIS不使用svc文件
  8. thinkphp js带参数跳转页面
  9. android本地socket正常,【报Bug】Android 本地打包 websocket 出错
  10. linux string
  11. [转]ubuntu使用meld/beyond compare 做git的diff工具
  12. 解决矩池云使用中ssh链接的时候日志丢失
  13. 【java】数据流的读写
  14. [postgresql]postgresql的聚合函数sql实例
  15. ELF文件加载与动态链接(一)
  16. SAP BW常用后台事务码
  17. win7触摸板怎么关闭_笔记本电脑触摸板快速关闭,避免误碰影响操作
  18. pcb 受潮_PCB受潮影响性能有什么好的处理方法?
  19. 量子计算机平行宇宙,【宇宙探秘】量子永生?量子纠缠可以推断出平行宇宙,再无真正意义上的死亡?...
  20. 感恩人生的每一段经历

热门文章

  1. Java判断文件类型
  2. input 换行_Python输出数据print,获取输入数据input,基础入门
  3. hdu4908 中位数子串
  4. hdu2899 三分
  5. 【错误记录】Groovy 报错 ( Execution failed for task ‘:compileGroovy‘. > org/apache/tools/ant/taskdefs/Java )
  6. 【Flutter】ListView 列表高级功能 ( ScrollController 上拉加载更多 )
  7. 【错误记录】Flutter 构建报错 ( Because xxx requires SDK version >=2.12.0-0 <3.0.0, versio | Dart SDK 版本低 )
  8. 【计算机网络】传输层 : TCP 连接管理 ( TCP 连接建立 | 三次握手 | TCP 连接释放 | 四次挥手 )
  9. 【Android 应用开发】BluetoothClass详解
  10. Python进阶03 模块