zoukankan      html  css  js  c++  java
  • jquery 源码分析十一

    这篇开始分析Sizzle中的终极匹配器。

    首先讲一下普通情况下,如:div a的匹配。在matcherFromToken函数中,可以看出匹配函数的组装方式,见源码:

    if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
        matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
    } else {
        matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );

    根据不同的tokens.type来生成不同的匹配函数,匹配函数检测时从右到左,对于body div的情况,首先检测div。原理是将传入的element判断TAG是否符合,调用Filter中函数:

    "TAG": function( nodeNameSelector ) {
        var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
        return nodeNameSelector === "*" ?
            function() { return true; } :
            function( elem ) {
                return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
            };
    },

    然后回到打包其的函数elementMatcher中:

    function elementMatcher( matchers ) {
        return matchers.length > 1 ?
            function( elem, context, xml ) {
                var i = matchers.length;
                while ( i-- ) {
                    if ( !matchers[i]( elem, context, xml ) ) {
                        return false;
                    }
                }
                return true;
            } :
            matchers[0];
    }

    接下来就是addCombinator函数中返回的函数的运行了,这个是由于body div中的' '形成的一个选择符函数,通过函数的运行,使得elem变量从原来传入的div元素,变为了body元素,并直接在此基础上运行下一步筛选函数,最后将结果缓存,返回。

    function( elem, context, xml ) {
        var oldCache, outerCache,
            newCache = [ dirruns, doneName ];
    
        // 不能再xml节点上设置额外信息,所以不能使用cache
        if ( xml ) {
            while ( (elem = elem[ dir ]) ) {
                if ( elem.nodeType === 1 || checkNonElements ) {
                    if ( matcher( elem, context, xml ) ) {
                        return true;
                    }
                }
            }
        } else {
            while ( (elem = elem[ dir ]) ) {
                if ( elem.nodeType === 1 || checkNonElements ) {
                    outerCache = elem[ expando ] || (elem[ expando ] = {});
                    if ( (oldCache = outerCache[ dir ]) &&
                        oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
    
                        // 有缓存且符合关系的话就直接返回不需调用matcher了
                        return (newCache[ 2 ] = oldCache[ 2 ]);
                    } else {
                        outerCache[ dir ] = newCache;
    
                        // 在这里就开始运行下一步筛选函数了,即更深层嵌套的函数matcher
                        if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
                            return true;
                        }
                    }
                }
            }
        }
    };

    然后追踪到matcher,可以发现其又进入了一个elementMatcher函数中,在这个函数中,我们观察matchers变量,可以发现其已经是到达最顶端了,matchers里主要是检测下一个是不是body元素,和document相关的东西:

    按照从后到前的顺序,先运行检测body的函数。

    ===============================分割线=================================

    以上是普通的情况,当设计到pseudos时,就会调用setMatcher来完成剩下的匹配,先上源码:

    function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
        // 对于在pseudos后面的选择符匹配函数
        if ( postFilter && !postFilter[ expando ] ) {
            postFilter = setMatcher( postFilter );
        }
        if ( postFinder && !postFinder[ expando ] ) {
            postFinder = setMatcher( postFinder, postSelector );
        }
        return markFunction(function( seed, results, context, xml ) {
            var temp, i, elem,
                preMap = [],
                postMap = [],
                preexisting = results.length,
    
                // 得到初始匹配的elems
                elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
    
                // 首先是将元素通过前置的筛选工作,得到pseudos处理前所有符合的函数
                matcherIn = preFilter && ( seed || !selector ) ?
                    condense( elems, preMap, preFilter, context, xml ) :
                    elems,
    
                matcherOut = matcher ?
                    //If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
                    postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
    
                        // ...intermediate processing is necessary
                        [] :
    
                        // ...otherwise use results directly
                        results :
                    matcherIn;
    
            // 找到主要的匹配项
            if ( matcher ) {
                matcher( matcherIn, matcherOut, context, xml );
            }
    
            // 调用postFilter
            if ( postFilter ) {
                temp = condense( matcherOut, postMap );
                postFilter( temp, [], context, xml );
    
                // 对于未匹配的元素,将其移到matcherIn
                i = temp.length;
                while ( i-- ) {
                    if ( (elem = temp[i]) ) {
                        matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
                    }
                }
            }
    
            if ( seed ) {
                if ( postFinder || preFilter ) {
                    if ( postFinder ) {
                        temp = [];
                        i = matcherOut.length;
                        while ( i-- ) {
                            if ( (elem = matcherOut[i]) ) {
                                // 恢复matcherIn
                                temp.push( (matcherIn[i] = elem) );
                            }
                        }
                        postFinder( null, (matcherOut = []), temp, xml );
                    }
    
                    // 将匹配的元素放入results,来保证两者同步
                    i = matcherOut.length;
                    while ( i-- ) {
                        if ( (elem = matcherOut[i]) &&
                            (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
    
                            seed[temp] = !(results[temp] = elem);
                        }
                    }
                }
    
            // 将元素放入result中,通过postFinder(如果有定义的话)
            } else {
                matcherOut = condense(
                    matcherOut === results ?
                        matcherOut.splice( preexisting, matcherOut.length ) :
                        matcherOut
                );
                if ( postFinder ) {
                    postFinder( null, results, matcherOut, xml );
                } else {
                    push.apply( results, matcherOut );
                }
            }
        });
    }

    我们可以看到,其中调用了许多次condense函数来完成筛选,源码如下:

    function condense( unmatched, map, filter, context, xml ) {
        var elem,
            newUnmatched = [],
            i = 0,
            len = unmatched.length,
            mapped = map != null;
    
        for ( ; i < len; i++ ) {
            if ( (elem = unmatched[i]) ) {
                if ( !filter || filter( elem, context, xml ) ) {
                    newUnmatched.push( elem );
                    if ( mapped ) {
                        map.push( i );
                    }
                }
            }
        }
    
        return newUnmatched;
    }

    condense对符合filter的元素放入到返回中,并同时添加到传入的map中。

    接下来就是生产最终匹配器的函数matcherFromGroupMatchers,源码如下:

    function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
        var bySet = setMatchers.length > 0,
            byElement = elementMatchers.length > 0,
            superMatcher = function( seed, context, xml, results, outermost ) {
                var elem, j, matcher,
                    matchedCount = 0,
                    i = "0",
                    unmatched = seed && [],
                    setMatched = [],
                    contextBackup = outermostContext,
                    // 必须有seed或者外围的context
                    elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
                    // 如果是outermost matcher的话,使用dirruns
                    dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
                    len = elems.length;
    
                if ( outermost ) {
                    outermostContext = context !== document && context;
                }
    
                // 对于通过elementMatchers的元素,直接添加到result中
                // 将i保持为字符串,这样如果没有元素的话,matchedCount就会显示为'00'
                for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
                    if ( byElement && elem ) {
                        j = 0;
                        while ( (matcher = elementMatchers[j++]) ) {
                            if ( matcher( elem, context, xml ) ) {
                                results.push( elem );
                                break;
                            }
                        }
                        if ( outermost ) {
                            dirruns = dirrunsUnique;
                        }
                    }
    
                    // 对于未匹配的元素尝试setMatcher
                    if ( bySet ) {
                        // 首先确保通过了所有的elementMatcher检验
                        if ( (elem = !matcher && elem) ) {
                            matchedCount--;
                        }
    
                        // 放入unmatched
                        if ( seed ) {
                            unmatched.push( elem );
                        }
                    }
                }
    
                // 使用setMatchers中的匹配对未匹配的进行检验
                matchedCount += i;
                if ( bySet && i !== matchedCount ) {
                    j = 0;
                    while ( (matcher = setMatchers[j++]) ) {
                        matcher( unmatched, setMatched, context, xml );
                    }
    
                    if ( seed ) {
                        // 将匹配element全部整合,准备用于排序
                        if ( matchedCount > 0 ) {
                            while ( i-- ) {
                                if ( !(unmatched[i] || setMatched[i]) ) {
                                    setMatched[i] = pop.call( results );
                                }
                            }
                        }
    
                        // 丢弃index值,来保证拿到的只是匹配的元素
                        setMatched = condense( setMatched );
                    }
    
                    // 然后将整合后的元素再放回到results中
                    push.apply( results, setMatched );
    
                    // Seedless set matches succeeding multiple successful matchers stipulate sorting
                    if ( outermost && !seed && setMatched.length > 0 &&
                        ( matchedCount + setMatchers.length ) > 1 ) {
    
                        Sizzle.uniqueSort( results );
                    }
                }
    
                // Override manipulation of globals by nested matchers
                if ( outermost ) {
                    dirruns = dirrunsUnique;
                    outermostContext = contextBackup;
                }
    
                return unmatched;
            };
    
        return bySet ?
            markFunction( superMatcher ) :
            superMatcher;
    }

    这篇就主要先粗略的讲解下这些内容,在后面会继续分析这些函数的调用,详见后面的博客(马上要断网了,赶紧撤)

  • 相关阅读:
    85. Maximal Rectangle
    120. Triangle
    72. Edit Distance
    39. Combination Sum
    44. Wildcard Matching
    138. Copy List with Random Pointer
    91. Decode Ways
    142. Linked List Cycle II
    异或的性质及应用
    64. Minimum Path Sum
  • 原文地址:https://www.cnblogs.com/cyITtech/p/3667340.html
Copyright © 2011-2022 走看看