最近一直在研究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 [ 源码分析 ]相关推荐

  1. Tomcat Filter 源码分析

    Filter 概述 Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter. 通过Filter技术,开发人 ...

  2. Envoy 源码分析--network L4 filter manager

    目录 Envoy 源码分析--network L4 filter manager FilterManagerImpl addWriteFilter addReadFilter addFilter in ...

  3. jQuery源码分析之实例find和filter方法的区别七问

    问题1:jQuery.filter的源码是什么? jQuery.filter = function( expr, elems, not ) {var elem = elems[ 0 ];//如果含有第 ...

  4. Spark源码分析之七:Task运行(一)

    在Task调度相关的两篇文章<Spark源码分析之五:Task调度(一)>与<Spark源码分析之六:Task调度(二)>中,我们大致了解了Task调度相关的主要逻辑,并且在T ...

  5. Solr初始化源码分析-Solr初始化与启动

    用solr做项目已经有一年有余,但都是使用层面,只是利用solr现有机制,修改参数,然后监控调优,从没有对solr进行源码级别的研究.但是,最近手头的一个项目,让我感觉必须把solrn内部原理和扩展机 ...

  6. Nginx源码分析:核心数据结构ngx_cycle_t与内存池概述

    nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> 核心数据结构与内存池概述 在Nginx中的核心数据结构就是ngx_cycle_t结构,在初始 ...

  7. djangorestframework源码分析1:generics中的view执行流程

    djangorestframework源码分析 本文环境python3.5.2,djangorestframework (3.5.1)系列 djangorestframework源码分析-generi ...

  8. Django源码分析10:makemigrations命令概述

    django源码分析 本文环境python3.5.2,django1.10.x系列 django源码分析-makemigrations命令概述 Django项目中的数据库管理命令就是通过makemig ...

  9. Django源码分析8:单元测试test命令浅析

    django源码分析 本文环境python3.5.2,django1.10.x系列 django源码分析-test命令分析 Django项目中提供了,test命令行命令来执行django的单元测试,该 ...

最新文章

  1. 一刻钟精通正则表达式
  2. Ext FormPanel布局 (一行显示两对控件元素)
  3. python新手入门总结_初学python的操作难点总结(新手必看篇)
  4. OpenCV与图像处理学习七——传统图像分割之阈值法(固定阈值、自适应阈值、大津阈值)
  5. 微软 Small Basic
  6. SpringBoot 配置 文件 mybatis type-aliases-package
  7. 使用MybatisPlus在实体中添加数据库表中不存在的字段
  8. 洛谷——P1025 数的划分
  9. 这是一本零基础学习 Python 的好书
  10. 《从问题到程序:用Python学编程和计算》——2.4 字符串
  11. SQL Server 2008无日志文件附加数据库
  12. 解决关灯游戏(Lights Off)
  13. 如何查询出指定地点对应的经纬度(高德地图)
  14. 基于AI分子力场模拟分子动力学
  15. 【沙龙干货分享】你要知道的N个Android适配问题
  16. int i=-20; unsigned int j = 10; i+j;的问题
  17. 为什么四大文明古国到现在只剩中国了
  18. php各版本共存方法,PHP多版本共存解决方案图解
  19. 电脑(伪)大神装B必备,来学几个windows脚本命令
  20. Navigating to current location (/login) is not allowed

热门文章

  1. VSCODE: Merge-conflict设置
  2. 图解算法 使用Java
  3. 按光在光纤中的传输模式可将光纤分为单模光纤和多模光纤两种
  4. 信息系统项目管理师-项目沟通管理
  5. 数据流图DFD --详细介绍
  6. 软工系列之--数据流图(DFD图)
  7. 交通运输综合管理信息平台建设方案(附下载)
  8. 线下店迎来“文艺复兴”,三只松鼠哪里寻“独门妙方”?
  9. android关于 text_to_speach的使用(tts)
  10. JS实现简单的网页文本转语音阅读