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

    xiaoxiao2024-01-03  96

    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。

    相关资源:jQuery技术内幕 深入解析jQuery架构设计与实现原理
    最新回复(0)