第十二课:Sizzle引擎详解
这篇博客难度太大,跟前端开发其实没什么关系,如果你想成为大牛,那就去了解下吧。如果你还不想,那可以忽略,毕竟面试官也不会问到这里来,因为他也不太懂。呵呵。
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引擎详解相关推荐
- MySQL数据库,从入门到精通:第十二篇——MySQL数据类型详解
MySQL数据库,从入门到精通:第十二篇--MySQL数据类型详解 第 12 章_MySQL数据类型精讲 1. MySQL中的数据类型 2. 整数类型 2. 1 类型介绍 2. 2 可选属性 2. 2 ...
- (十二)命令模式详解(故事版)- 转
作者:zuoxiaolong8810(左潇龙),转载请注明出处. 背景:小左是魔都某公司技术部的一名屌丝程序猿,每天的工作就是维护一个20世纪的古董级项目,由于公司不大,所以公司很多制度不太完善,导致 ...
- (二十二)访问者模式详解(伪动态双分派) - 转
作者:zuoxiaolong8810(左潇龙),转载请注明出处. 本次LZ和各位分享一下访问者模式,从场景.设计初衷以及实现方面来说,访问者模式算是LZ即将写到的24种设计模式当中,最复杂也是最难理解 ...
- 面渣逆袭:Redis连环五十二问,图文详解,这下面试稳了
大家好,我是老三,面渣逆袭系列继续,这节我们来搞定Redis--不会有人假期玩去了吧?不会吧? 基础 1.说说什么是Redis? Redis是一种基于键值对(key-value)的NoSQL数据库. ...
- 【Android游戏开发二十二】(图文详解)游戏中灵活实现动画播放!简述J2me的游戏类库与Android游戏开发!
本站文章均为 李华明Himi 原创,转载务必在明显处注明:(作者新浪微博: @李华明Himi ) 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/andr ...
- 零基础班第十五课 - Hive DDL详解
第一章:上次课回顾 1.1 Hive部署过程中出现的坑 第二章:Hive DDL语句 2.1 图解Hive结构 2.2 创建数据库 2.2.1 数据库建表语句 2.2.2 数据库解析 2.2.3 修改 ...
- Javascript(十二)javascript 事件详解
一.事件定义 关于事件实际上我们已经初步接触过了,指的就是用户与浏览器交互的一瞬间. 我们通过为指定事件绑定回调函数的形式来处理事 件,当指定事件触发以后我们的回调函数就会被调用,这样我们的页面就可以 ...
- NIO详解(十二):AsynchronousFileChannel详解
1. 概述 Java NIO中的FileChannel是一个连接到文件的通道.可以通过文件通道读写文件.FileChannel无法设置为非阻塞模式,他总是运行在阻塞模式下.在Java 7中,Async ...
- (十二)命令模式详解(故事版)
作者:zuoxiaolong8810(左潇龙),转载请注明出处. 背景:小左是魔都某公司技术部的一名屌丝程序猿,每天的工作就是维护一个20世纪的古董级项目,由于公司不大,所以公司很多制度不太完善,导致 ...
最新文章
- 数据科学的积累:海平面下的冰山 | 清华信息技术研究院郑方
- python3入门教程-Python3 入门教程 简单但比较不错
- Watch out for these 10 common pitfalls of experienced Java developers architects--转
- 【PM模块】外包服务、工作清场管理、预防性维护
- 【Django】ORM操作#2
- 2012.2.18-silverlight设计器崩溃
- WCF部署到IIS不使用svc文件
- thinkphp js带参数跳转页面
- android本地socket正常,【报Bug】Android 本地打包 websocket 出错
- linux string
- [转]ubuntu使用meld/beyond compare 做git的diff工具
- 解决矩池云使用中ssh链接的时候日志丢失
- 【java】数据流的读写
- [postgresql]postgresql的聚合函数sql实例
- ELF文件加载与动态链接(一)
- SAP BW常用后台事务码
- win7触摸板怎么关闭_笔记本电脑触摸板快速关闭,避免误碰影响操作
- pcb 受潮_PCB受潮影响性能有什么好的处理方法?
- 量子计算机平行宇宙,【宇宙探秘】量子永生?量子纠缠可以推断出平行宇宙,再无真正意义上的死亡?...
- 感恩人生的每一段经历
热门文章
- Java判断文件类型
- input 换行_Python输出数据print,获取输入数据input,基础入门
- hdu4908 中位数子串
- hdu2899 三分
- 【错误记录】Groovy 报错 ( Execution failed for task ‘:compileGroovy‘. > org/apache/tools/ant/taskdefs/Java )
- 【Flutter】ListView 列表高级功能 ( ScrollController 上拉加载更多 )
- 【错误记录】Flutter 构建报错 ( Because xxx requires SDK version >=2.12.0-0 <3.0.0, versio | Dart SDK 版本低 )
- 【计算机网络】传输层 : TCP 连接管理 ( TCP 连接建立 | 三次握手 | TCP 连接释放 | 四次挥手 )
- 【Android 应用开发】BluetoothClass详解
- Python进阶03 模块