Sizzle.filter [ 源码分析 ]
最近一直在研究Sizzle选择器,对于其中的原理确实不得不佩服!
Sizzle中的filter方法,主要负责块表达式过滤元素集合,在方法内部会调用Sizzle.selector.fitler方法执行过滤操作。
Sizzle.filter主要分5个关键步骤:
1 使用LeftMatch确定表达式类型。
2 调用Sizzle.selectors.preFilter预过虑函数,执行过滤前的修正。
3 调用Sizzle.selectors.filter[ type ] 中对应的过滤函数,执行过滤操作,如果返回false,刚将元素集合中的对应位置的元素替换为false;
4 删除表达式中已过滤的部分
5 重复1 - 4 步骤
源码如下:
Sizzle.filter = function( expr, set, inplace, not ) {//expr 块表达式//set 待过滤的元素集合//inplace 是否替换,如果为true,那么当set中的元素与expr不匹配时,刚将不匹配的元素替换为false,//否则,构造新的数组,只保留匹配的元素//not: 如果为true,则去掉匹配元素,保留不匹配元素,如果为false,则保留匹配元素,去掉不匹配元素var match, anyFound,type, found, item, filter, left,i, pass,old = expr,result = [],curLoop = set,isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );//while 循环,无限循环用expr过滤set元素,直到expr为空,因为在最后会将已经匹配过的部分删除,所以expr会越来越短while ( expr && set.length ) {for ( type in Expr.filter ) {//这里用来确定表达式类型,根据leftMatch正则//这里是match正则,LeftMatch只是要该正则加上了前缀和后缀/*match: {ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},*/if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {filter = Expr.filter[ type ];//确定前缀left = match[1];anyFound = false;match.splice(1,1);//这里官方说是匹配 \\ 如果是 \\ 那么表示后面的元素都是被转义,刚不需要再去过滤,//不过个人觉得这个地方似乎无效的 left.subster(left.length - 1) //这个字符的长度只会是1 怎么会和 \\ 相等呢if ( left.substr( left.length - 1 ) === "\\" ) {continue;}//重置result为空数组,用于缩小候选集,result用来存放通过过滤的元素if ( curLoop === result ) {result = [];}if ( Expr.preFilter[ type ] ) {//这里会进行预过滤操作,主要对表达式进行修改正,如转义\\,取出空格等//针对不同和类型,会有不同的方式,详情可以见preFilter方法match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );/*match:1 true: 继续需要执行过滤,尚不到执行过虑函数的时候,直接执行continue,不再去调用filter方法。如pos,child2 false: 已经执行了过滤,缩小了候选集如:CLASS3 字符串: 修正之后的过滤参数,后面会继续调用对应的过虑函数*/if ( !match ) {anyFound = found = true;} else if ( match === true ) {continue;}}//返回的是修正的过滤参数,刚继续执行if ( match ) {//遍历候选集中的元素for ( i = 0; (item = curLoop[i]) != null; i++ ) {//元素存在if ( item ) {//对其进行过滤,返回结果found = filter( item, match, i, curLoop );//这里与 not 进行 异或 操作pass = not ^ found;//为替换模式,并且found 不为空if ( inplace && found != null ) {//如果通过,那么为trueif ( pass ) {anyFound = true;} else {//否则将元素替换为falsecurLoop[i] = false;}} else if ( pass ) {//这要需要注意的是既然pass为真了, 那么就不需要判断了found,因为pass为found与not异或的结果//如果通过了,并且为非替换模式,那么将元素放入到新的数组result中result.push( item );anyFound = true;}}}}//found不为undefinedif ( found !== undefined ) {if ( !inplace ) {//非替换模式,将结果复制给curLoop,curLoop = result;}//删除已经过滤过了的部分表达式expr = expr.replace( Expr.match[ type ], "" );//不匹配,返回空if ( !anyFound ) {return [];}//这里的break,说明已经进行过一次过虑,已经找到对应的type,可以选择跳出当前type的循环,break;}}}// 这里主要是匹配,如果最后过滤的表达式没有变化,那么认为过滤表达式有问题if ( expr === old ) {if ( anyFound == null ) {Sizzle.error( expr );} else {break;}}//备份expr,继续循环old = expr;}//返回过滤的结果return curLoop;
};
Sizzle.filter [ 源码分析 ]相关推荐
- Tomcat Filter 源码分析
Filter 概述 Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter. 通过Filter技术,开发人 ...
- Envoy 源码分析--network L4 filter manager
目录 Envoy 源码分析--network L4 filter manager FilterManagerImpl addWriteFilter addReadFilter addFilter in ...
- jQuery源码分析之实例find和filter方法的区别七问
问题1:jQuery.filter的源码是什么? jQuery.filter = function( expr, elems, not ) {var elem = elems[ 0 ];//如果含有第 ...
- Spark源码分析之七:Task运行(一)
在Task调度相关的两篇文章<Spark源码分析之五:Task调度(一)>与<Spark源码分析之六:Task调度(二)>中,我们大致了解了Task调度相关的主要逻辑,并且在T ...
- Solr初始化源码分析-Solr初始化与启动
用solr做项目已经有一年有余,但都是使用层面,只是利用solr现有机制,修改参数,然后监控调优,从没有对solr进行源码级别的研究.但是,最近手头的一个项目,让我感觉必须把solrn内部原理和扩展机 ...
- Nginx源码分析:核心数据结构ngx_cycle_t与内存池概述
nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> 核心数据结构与内存池概述 在Nginx中的核心数据结构就是ngx_cycle_t结构,在初始 ...
- djangorestframework源码分析1:generics中的view执行流程
djangorestframework源码分析 本文环境python3.5.2,djangorestframework (3.5.1)系列 djangorestframework源码分析-generi ...
- Django源码分析10:makemigrations命令概述
django源码分析 本文环境python3.5.2,django1.10.x系列 django源码分析-makemigrations命令概述 Django项目中的数据库管理命令就是通过makemig ...
- Django源码分析8:单元测试test命令浅析
django源码分析 本文环境python3.5.2,django1.10.x系列 django源码分析-test命令分析 Django项目中提供了,test命令行命令来执行django的单元测试,该 ...
最新文章
- 一刻钟精通正则表达式
- Ext FormPanel布局 (一行显示两对控件元素)
- python新手入门总结_初学python的操作难点总结(新手必看篇)
- OpenCV与图像处理学习七——传统图像分割之阈值法(固定阈值、自适应阈值、大津阈值)
- 微软 Small Basic
- SpringBoot 配置 文件 mybatis type-aliases-package
- 使用MybatisPlus在实体中添加数据库表中不存在的字段
- 洛谷——P1025 数的划分
- 这是一本零基础学习 Python 的好书
- 《从问题到程序:用Python学编程和计算》——2.4 字符串
- SQL Server 2008无日志文件附加数据库
- 解决关灯游戏(Lights Off)
- 如何查询出指定地点对应的经纬度(高德地图)
- 基于AI分子力场模拟分子动力学
- 【沙龙干货分享】你要知道的N个Android适配问题
- int i=-20; unsigned int j = 10; i+j;的问题
- 为什么四大文明古国到现在只剩中国了
- php各版本共存方法,PHP多版本共存解决方案图解
- 电脑(伪)大神装B必备,来学几个windows脚本命令
- Navigating to current location (/login) is not allowed