开发者社区> 华章计算机> 正文

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。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
一起谈.NET技术,Microsoft NLayerApp案例理论与实践 - 多层架构与应用系统设计原则
  在对NLayerApp实际项目进行讨论之前,让我们首先学习一下(或者应该说重温一下)分层/多层架构与应用系统设计原则。很多朋友会认为这些都是老掉牙的内容,只要是软件从业人员,都会对这些内容非常熟悉。
969 0
一起谈.NET技术,系统架构技能之设计模式—代理模式
  一、上篇回顾   很久没有更新设计模式系列的文章了,有了很多热心朋友的反馈,我决定继续将这个系列赶快写完,最近由于过年了,有很多相关的事宜要做,所以没有时间来写,也是对大家的说下抱歉,感觉写文章的时间越来越少了,不过我会努力,尽快将这个系列写完,与大家共勉,希望大家有什么意见或建议,都可以帮我提出来,我好改进,谢谢!。
866 0
《 自动化测试最佳实践:来自全球的经典自动化测试案例解析》一一3.6 我们的心得
本节书摘来自华章出版社《 自动化测试最佳实践:来自全球的经典自动化测试案例解析 》一 书中的第3章,第3. 6节,作者:(英)Dorothy Graham Mark Fewster 著 ,更多章节内容可以访问云栖社区“华章计算机”公众号查看
1310 0
《Linux内核设计的艺术:图解Linux操作系统架构设计与实现原理》——2.11 初始化硬盘
本节书摘来自华章计算机《Linux内核设计的艺术:图解Linux操作系统架构设计与实现原理》一书中的第2章,第2.11节,作者:新设计团队著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
876 0
《 自动化测试最佳实践:来自全球的经典自动化测试案例解析》一一3.1 本案例研究的背景
本节书摘来自华章出版社《 自动化测试最佳实践:来自全球的经典自动化测试案例解析 》一 书中的第3章,第3. 1 节,作者:(英)Dorothy Graham Mark Fewster 著 ,更多章节内容可以访问云栖社区“华章计算机”公众号查看
1030 0
《Linux内核设计的艺术:图解Linux操作系统架构设计与实现原理》——2.13 开启中断
本节书摘来自华章计算机《Linux内核设计的艺术:图解Linux操作系统架构设计与实现原理》一书中的第2章,第2.13节,作者:新设计团队著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
886 0
《 自动化测试最佳实践:来自全球的经典自动化测试案例解析》一一3.3 如何实施TiP
本节书摘来自华章出版社《 自动化测试最佳实践:来自全球的经典自动化测试案例解析 》一 书中的第3章,第3. 节,作者:(英)Dorothy Graham Mark Fewster 著 ,更多章节内容可以访问云栖社区“华章计算机”公众号查看
1139 0
《 自动化测试最佳实践:来自全球的经典自动化测试案例解析》一一3.2 将测试移到云端
本节书摘来自华章出版社《 自动化测试最佳实践:来自全球的经典自动化测试案例解析 》一 书中的第3章,第3.2 节,作者:(英)Dorothy Graham Mark Fewster 著 ,更多章节内容可以访问云栖社区“华章计算机”公众号查看
1106 0
10059
文章
0
问答
来源圈子
更多
+ 订阅
文章排行榜
最热
最新
相关电子书
更多
OceanBase 入门到实战教程
立即下载
阿里云图数据库GDB,加速开启“图智”未来.ppt
立即下载
实时数仓Hologres技术实战一本通2.0版(下)
立即下载