jQuery技术内幕:深入解析jQuery架构设计与实现原理. 3.7 Sizzle.filter( expr, set, inplace, not )

简介:

3.7 Sizzle.filter( expr, set, inplace, not )

方法Sizzle.filter( expr, set, inplace, not )负责用块表达式过滤元素集合。在该方法内部,将用过滤函数集Sizzle.selectors.filter中的过滤函数来执行过滤操作。

方法Sizzle.filter( expr, set, inplace, not )实现的5个关键步骤如下:

1)首先用正则集合Sizzle.selectors.leftMatch中的正则确定块表达式类型。

2)然后调用预过滤函数集Sizzle.selectors.preFilter中对应类型的预过滤函数,执行过滤前的修正操作。

3)调用过滤函数集Sizzle.selectors.filter[ type ]中对应类型的过滤函数,执行过滤操作,如果过滤函数返回false,则把元素集合中对应位置的元素替换为false。

4)最后删除块表达式中已过滤的部分。

5)重复第1)~4)步,直至块表达式变为空字符串。

下面来看看该方法的源码实现。

1.定义Sizzle.filter( expr, set, inplace, not )

相关代码如下所示:

4086 Sizzle.filter = function( expr, set, inplace, not ) {

第4086行:定义方法Sizzle.filter( expr, set, inplace, not ),它接受 4 个参数:

参数expr:块表达式。

参数set:待过滤的元素集合。

参数inplace:布尔值。如果为true,则将元素集合set中与选择器表达式不匹配的元素设置为false;如果不为true,则重新构造一个元素数组并返回,只保留匹配元素。

参数not:布尔值。如果为true,则去除匹配元素,保留不匹配元素;如果不为true,则去除不匹配元素,保留匹配元素。

2.?用块表达式expr过滤元素集合set,直到expr为空

相关代码如下所示:

4087     var match, anyFound,

4088         type, found, item, filter, left,

4089         i, pass,

4090         old = expr,

4091         result = [],

4092         curLoop = set,

4093         isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );

4094

4095     while ( expr && set.length ) {

第4095行:用块表达式expr过滤元素集合set,直到expr变为空字符串。如果候选集set变为空数组,则没有必要继续执行过滤操作。

(1)遍历块过滤函数集Sizzle.selectors.filter

相关代码如下所示:

4096         for ( type in Expr.filter ) {

第4096行:遍历块过滤函数集Sizzle.selectors.filter,调用其中的过滤函数执行过滤操作。块过滤函数集Sizzle.selectors.filter中定义了PSEUDO、CHILD、ID、TAG、CLASS、ATTR、POS对应的过滤函数,具体请参见3.9.7节。

(2)确定块表达式类型Sizzle.selectors.leftMatch[ type ]

相关代码如下所示:

4097             if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {

4098                 filter = Expr.filter[ type ];

4099                 left = match[1];

4100

4101                 anyFound = false;

4102

4103                 match.splice(1,1);

4104

4105                 if ( left.substr( left.length - 1 ) === "\\" ) {

4106                     continue;

4107                 }

4108

第4097行:检查每个表达式类型type在Sizzle.selectors.leftMatch中对应的正则是否匹配块表达式expr,如果匹配,则可以确定块表达式的类型。

第4105~4107行:如果匹配正则的内容以反斜杠"\\"开头,表示反斜杠"\\"之后的字符被转义了,不是期望的类型,这时会认为类型匹配失败。

(3)调用预过滤函数Sizzle.selectors.preFilter[ type ]

相关代码如下所示:

4109                 if ( curLoop === result ) {

4110                     result = [];

4111                 }

4112

4113                 if ( Expr.preFilter[ type ] ) {

4114                     match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );

4115

4116                     if ( !match ) {

4117                        anyFound = found = true;

4118

4119                     } else if ( match === true ) {

4120                        continue;

4121                     }

4122                 }

4123

第4109~4111行:用于缩小候选集。

第4113~4122行:如果在预过滤函数集Sizzle.selectors.preFilter中存在对应的预过滤函数,则调用,执行过滤前的修正操作。预过滤函数负责进一步修正过滤参数,具体请参见3.9.4节。

第4116~4121行:预过滤函数有3种返回值:

false:已经执行了过滤,缩小了候选集,例如,CLASS。

true:需要继续执行预过滤,尚不到执行过滤函数的时候,例如,POS、CHILD。

字符串:修正后的过滤参数(通常是块表达式),后面会继续调用对应的过滤函数。

(4)调用过滤函数Sizzle.selectors.filter[ type ]

相关代码如下所示:

4124                 if ( match ) {

4125                     for ( i = 0; (item = curLoop[i]) != null; i++ ) {

4126                         if ( item ) {

4127                             found = filter( item, match, i, curLoop );

4128                             pass = not ^ found;

4129

4130                             if ( inplace && found != null ) {

4131                                 if ( pass ) {

4132                                     anyFound = true;

4133

4134                                 } else {

4135                                     curLoop[i] = false;

4136                                 }

4137

4138                             } else if ( pass ) {

4139                                 result.push( item );

4140                                 anyFound = true;

4141                             }

4142                         }

4143                     }

4144                 }

4145

第4124~4144行:遍历元素集合curLoop,对其中的每个元素执行过滤函数,检测元素是否匹配。

第4127~4128行:变量found表示当前元素是否匹配过滤表达式;变量pass表示当前元素item是否可以通过过滤表达式的过滤。如果变量found为true,表示匹配,此时如果未指定参数not,则变量pass为true;如果变量found为false,表示不匹配,此时如果参数not为true,则变量pass为true;其他情况下,变量pass为false。

第4130~4141行:如果参数inplace为true,则将与块表达式expr不匹配的元素设置为false;如果参数inplace不是true,则重新构造一个元素数组,只保留匹配元素,即会不断地缩小元素集合。

(5)删除块表达式expr中已过滤的部分

相关代码如下所示:

4146                 if ( found !== undefined ) {

4147                     if ( !inplace ) {

4148                         curLoop = result;

4149                     }

4150

4151                     expr = expr.replace( Expr.match[ type ], "" );

4152

4153                     if ( !anyFound ) {

4154                         return [];

4155                     }

4156

4157                     break;

4158                 }

4159             }

4160         }

4161

第4146行:变量found是过滤函数Sizzle.selectors.filter[ type ]的返回值,如果不等于undefined,表示至少执行过一次过滤。大多数情况下,过滤操作发生在过滤函数中,不过也可能发生在预过滤函数中,例如,CLASS、POS、CHILD。

第4147~4149行:如果参数inplace不是true,则将新构建的元素数组赋值给变量curLoop,在下次循环时,会将result再次置为空数组(见第4109~4111行),然后存放通过过滤的元素(见第4130~4141行),然后再赋值给变量curLoop,即会不断地缩小元素集合。

第4151行:删除块表达式中已过滤过的部分,直至块表达式变为空字符串。用对象Sizzle.selectors.match中对应的正则匹配已过滤过的部分,具体请参见3.9.2节。

第4153~4155行:如果没有找到可以通过过滤的元素,直接返回一个空数组。

(6)如果块表达式没有发生变化,则认为不合法

相关代码如下所示:

4162         // Improper expression

4163         if ( expr === old ) {

4164             if ( anyFound == null ) {

4165                 Sizzle.error( expr );

4166

4167             } else {

4168                 break;

4169             }

4170         }

4171

4172         old = expr;

4173     }

4174

 

4178 Sizzle.error = function( msg ) {

4179     throw new Error( "Syntax error, unrecognized expression: " + msg );

4180 };

第4163~4172行:如果块表达式expr没有发生变化,说明前面的过滤没有生效,动不了块表达式expr分毫,此时如果没有找到可以通过过滤的元素,则认为块表达式expr不合法,抛出语法错误的异常。

3.?返回过滤后的元素集合,或缩减范围后的元素集合

相关代码如下所示:

4175     return curLoop;

4176 };

方法Sizzle.filter( expr, set, inplace, not )的执行过程可以总结为图3-6。

相关文章
|
2天前
|
Java
并发编程之线程池的底层原理的详细解析
并发编程之线程池的底层原理的详细解析
12 0
|
16天前
|
Linux 编译器 开发者
Linux设备树解析:桥接硬件与操作系统的关键架构
在探索Linux的庞大和复杂世界时🌌,我们经常会遇到许多关键概念和工具🛠️,它们使得Linux成为了一个强大和灵活的操作系统💪。其中,"设备树"(Device Tree)是一个不可或缺的部分🌲,尤其是在嵌入式系统🖥️和多平台硬件支持方面🔌。让我们深入了解Linux设备树是什么,它的起源,以及为什么Linux需要它🌳。
Linux设备树解析:桥接硬件与操作系统的关键架构
|
26天前
|
机器学习/深度学习 前端开发 Windows
【夯实技术基本功】「底层技术原理体系」全方位带你认识和透彻领悟正则表达式(Regular Expression)的开发手册(正则符号深入解析 )
【夯实技术基本功】「底层技术原理体系」全方位带你认识和透彻领悟正则表达式(Regular Expression)的开发手册(正则符号深入解析 )
31 0
|
30天前
|
存储 安全 编译器
【C++ 17 新功能 std::visit 】深入解析 C++17 中的 std::visit:从原理到实践
【C++ 17 新功能 std::visit 】深入解析 C++17 中的 std::visit:从原理到实践
70 0
|
13天前
|
存储 中间件 关系型数据库
数据库切片大对决:ShardingSphere与Mycat技术解析
数据库切片大对决:ShardingSphere与Mycat技术解析
21 0
|
26天前
|
安全 Java 数据安全/隐私保护
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
59 1
|
26天前
|
存储 NoSQL 算法
【Redis技术进阶之路】「底层源码解析」揭秘高效存储模型与数据结构底层实现(字典)(二)
【Redis技术进阶之路】「底层源码解析」揭秘高效存储模型与数据结构底层实现(字典)
40 0
|
1天前
|
缓存 JavaScript 前端开发
|
2天前
|
SQL 分布式计算 资源调度
一文解析 ODPS SQL 任务优化方法原理
本文重点尝试从ODPS SQL的逻辑执行计划和Logview中的执行计划出发,分析日常数据研发过程中各种优化方法背后的原理,覆盖了部分调优方法的分析,从知道怎么优化,到为什么这样优化,以及还能怎样优化。
|
2天前
|
JSON Java Maven
Javaweb之SpringBootWeb案例之 SpringBoot原理的详细解析
Javaweb之SpringBootWeb案例之 SpringBoot原理的详细解析
8 0
Javaweb之SpringBootWeb案例之 SpringBoot原理的详细解析

推荐镜像

更多