Sizzle一步步实现所有功能(基本筛选)

第二步:实现:first,:last,:eq(),even,odd,:gt(),:lt(); :header,:root,:taget; :not()。

;(function( window ){

var arr = [];

var push = arr.push;

var slice = arr.slice;

var select ;

var Expr;

// 标识

var expando = "sizzle" + 1 * new Date();

// http://www.w3.org/TR/css3-selectors/#whitespace

// 各种空白待穿正则字符串

var whitespace = "[\\x20\\t\\r\\n\\f]";

// 带空格选择器正则,记忆无空格选择器

// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier

var    identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+";

var pseudos = ":(" + identifier + ")(?:\\((" +

        // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:

        // 1. quoted (capture 3; capture 4 or capture 5)

        "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +

        // 2. simple (capture 6)

        "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +

        // 3. anything else (capture 2)

        ".*" +

        ")\\)|)";

// 属性选择器: http://www.w3.org/TR/selectors/#attribute-selectors

var    attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +

        // Operator (capture 2)

        "*([*^$|!~]?=)" + whitespace +

        // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"

        "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +

        "*\\]";

var rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" );

// 快速选择器正则 ID 或者 TAG(包括*) 或者 CLASS 选择器

var rquickExpr = /^(?:#([\w-]+)|(\w+|\*)|\.([\w-]+))$/;

// 连接符号

var rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" );

// 层级符号正则'>',' ','+','~'

var rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" );

var matchExpr = {

        "ID": new RegExp( "^#(" + identifier + ")" ),

        "CLASS": new RegExp( "^\\.(" + identifier + ")" ),

        "TAG": new RegExp( "^(" + identifier + "|[*])" ),

        "PSEUDO": new RegExp( "^" + pseudos ),

        "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +

            whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )

};

var rheader = /^h\d$/i;

// 浏览器代码正则

var rnative = /^[^{]+\{\s*\[native \w/;

// token缓存

var tokenCache = createCache();

// 编译缓存

var compilerCache = createCache();

// 入口

function Sizzle( selector, context, results){

    // 清除空格

    selector = selector.replace( rtrim, "$1" )

    var results = results || [];

    var match;

    var matcher;

    var elem;

    var m;

    var context = context || document;

    

    // 是否为最简选择器

    if( match = rquickExpr.exec( selector )){

        // Sizzle('#ID)

        if ( (m = match[1]) ) {

            elem = context.getElementById( m );

            if( elem ){

                results.push( elem );

            }

            return results;

            

        // Sizzle("TAG")

        }else if( (m = match[2]) ){

            push.apply( results, context.getElementsByTagName( selector ) );

            return results;

        

        // Sizzle(".CLASS")    

        }else if( (m = match[3]) ){

            // 支持getElementsByClassName

            if( support.getElementsByClassName ){

                push.apply( results, context.getElementsByClassName( m ) );

                return results;

            }

        }

    }

    // 复杂选择调到select

    return select( selector, context, results);

}

// 创建缓存函数

function createCache() {

    var keys = [];



    function cache( key, value ) {

        // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)

        if ( keys.push( key + " " ) > 10 ) {

            // Only keep the most recent entries

            delete cache[ keys.shift() ];

        }

        return (cache[ key + " " ] = value);

    }

    return cache;

}

// 函数标记函数

function markFunction( fn ) {

    fn[ expando ] = true;

    return fn;

}

// 错误函数

Sizzle.error = function( msg ) {

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

};

// 版本支持变量的对外访问入口

var support = Sizzle.support = {};



// 判断是否支持getElementsByClassName

// 支持: IE<9

support.getElementsByClassName = rnative.test( document.getElementsByClassName );

// 表达式对象

// 存放各类相对位置,各种查询函数,各种过滤函数等。

Expr = {

    relative: {

        ">": { dir: "parentNode", first: true },

        " ": { dir: "parentNode" },

        "+": { dir: "previousSibling", first: true },

        "~": { dir: "previousSibling" }

    },

    filter: {

        "TAG": function( nodeNameSelector ) {

            var nodeName = nodeNameSelector.toLowerCase();

            return nodeNameSelector === "*" ?

                function() { return true; } :

                function( elem ) {

                    return elem.nodeName.toLowerCase() === nodeName;

                };

        },

        "CLASS": function( className ) {

            var className = className.toLowerCase();

            return function( elem ) {

                    return elem.className.toLowerCase() === className;

            };

        },

        "PSEUDO": function( pseudo, argument ) {

            var fn = Expr.pseudos[ pseudo ];

            if ( fn[ expando ] ) {

                return fn( argument );

            }

            return fn;

        }

    },

    find: {

        "TAG": function( tag, context ) {

            return context.getElementsByTagName( tag );

        },

        "CLASS": support.getElementsByClassName&&function( tag, context ) {

            return context.getElementsByClassName( tag );

        },

    },

    // 筛选方法

    pseudos: {

        // not是个难点

        // superMatcher将结果存入restlts,未匹配的元素则返回

        // not两个路线一个是处理not参数中为复杂伪类筛选setMatcher

        // 一个是elementMatcher

        "not": markFunction(function( selector ){

                var results = [];

                var input = [];

                var matcher = compile( selector );

                return matcher[ expando ] ?  

                markFunction(function( seed, matches, context){

                    var elem;

                    var unmatched = matcher(seed, null, [] );

                    var i = seed.length;

                    while ( i-- ) {

                        if ( (elem = unmatched[i]) ) {

                            seed[i] = !(matches[i] = elem);

                        }

                    }

                }):

                function( elem, context ) {

                    input[0] = elem;

                    matcher( input, null, results );

                    return !results.pop();

                }

            }

        ),

        "target": function( elem ) {

            var hash = window.location && window.location.hash;

            return hash && hash.slice( 1 ) === elem.id;

        },

        "header": function( elem ) {

            return rheader.test( elem.nodeName );

        },

        "root": function( elem ) {

            return elem === document.documentElement;

        },

        // 以下为位置筛选,我们采用一个函数,但其index不同。

        // 用createPositionalPseudo生成一个新函数,这个函数的index数组根据位置不同而不同

        "first": createPositionalPseudo(

            function(){

                return [0];

            }

        ),

        "last":createPositionalPseudo(

            function( matchesIndex ,length){

                return [ length-1 ];

            }

        ),

        "eq": createPositionalPseudo(

            function( matchesIndex ,length, argument){

                return [ argument < 0 ? argument + length : argument ];

            }

        ),

        "even": createPositionalPseudo(

            function( matchesIndex, length ){

                for(var i = 0; i<length; i+=2){

                    matchesIndex.push(i);

                }

                return matchesIndex;

            }

        ),

        "odd": createPositionalPseudo(

            function( matchesIndex, length ){

                for(var i = 1; i<length; i+=2){

                    matchesIndex.push(i);

                }

                return matchesIndex;

            }

        ),

        "lt": createPositionalPseudo(

            function( matchesIndex ,length, argument){

                var i = argument < 0 ? argument + length : argument;

                while(i--){

                    matchesIndex.push(i);

                }

                return matchesIndex;

            }

        ),

        "gt": createPositionalPseudo(

            function( matchesIndex, length, argument){

                var i = argument < 0 ? argument + length : argument;

                while( ++i < length){

                    matchesIndex.push(i);

                }

                return matchesIndex;

            }

        ),

    }

}

// 返回一个函数,用于所有位置筛选

function createPositionalPseudo( fn ) {

    return markFunction( function( argument ){

        argument = + argument;

        return markFunction(function( seed, matches ) {

            var j;

            var matchIndexes = fn([],seed.length,argument);

            var i = matchIndexes.length;

            while(i--){

                if ( seed[ (j = matchIndexes[i]) ] ) {

                    seed[j] = !(matches[j] = seed[j]);

                }

            }

        })

    })

}

// tokenize函数

// 将选择器字符串转化为方便使用的数组对象形式

tokenize = Sizzle.tokenize = function( selector, parseOnly ) {

    var cached = tokenCache[ selector + " " ];

    

    // cached.slice生成新的数组,对其修改不会修改其引用缓存

    if ( cached ) {

        return cached.slice( 0 );

    }

    // 循环条件

    var soFar = selector;

    // 结果数组

    var groups = [];

    // 匹配参数

    var matched;

    // 一个独立的tokens

    var tokens;

    // 辅助变量

    var match;



    while ( soFar ) {



        //首次默认创建一个tokens

        //之后每碰到一个逗号新增一个新的tokens

        if ( !matched || (match = rcomma.exec( soFar )) ) {

            if ( match ) {

                // Don't consume trailing commas as valid

                soFar = soFar.slice( match[0].length ) || soFar;

            }

            groups.push( (tokens = []) );

        }

        

        matched = false;



        // 关系token

        if ( (match = rcombinators.exec( soFar )) ) {

            matched = match.shift();

            tokens.push({

                value: matched,

                // Cast descendant combinators to space

                type: match[0].replace( rtrim, " " )

            });

            soFar = soFar.slice( matched.length );

        }

        // TAG,CLASS,ID token

        for ( type in Expr.filter ) {

            if ((match = matchExpr[ type ].exec( soFar )) ) {

                matched = match.shift();

                tokens.push({

                    value: matched,

                    type: type,

                    matches: match

                });

                soFar = soFar.slice( matched.length );

            }

        }

        // 一次循环到这里三个条件都不符合没有匹配结果时,跳出。

        if ( !matched ) {

            break;

        }

    }

    // 意外跳出,soFar存在,报错。

    return soFar ?

            Sizzle.error( selector ) :

            // 缓存后转成新数组返回(预防修改缓存内容)

            tokenCache( selector, groups ).slice( 0 );

};

// 将tokens转化为selector字符串形式。

function toSelector( tokens ) {

    var i = 0,

        len = tokens.length,

        selector = "";

    for ( ; i < len; i++ ) {

        selector += tokens[i].value;

    }

    return selector;

}

// 压缩数组

// condense([undefined,1,2,3]) = [123];

function condense(matcherOut) {

    var newMatcherOut = [];

    var elem;

    for(var i =0; i< matcherOut.length;i++){

        if((elem = matcherOut[i])){

            newMatcherOut.push(elem);

        }

    }

    return newMatcherOut;

}

// 对多重上下文执行元素选择

// 用于上下文是数组的情况

// 服务于setMatcher返回函数的某些情况

function multipleContexts(selector,context,results){

    for(var i = 0;i<context.length;i++){

        Sizzle(selector, context[i],results);

    }

    return results;

}

// setMatcher筛选

// setMatcher是不同于elementMatcher的另一个方向,用来处理各种伪类筛选

function setMatcher( preFilter, selector, matcher, postFinder, postSelector){

    if ( postFinder && !postFinder[ expando ] ) {

        postFinder = setMatcher( postFinder, postSelector );

    }

    return markFunction(function( seed, results, context ) {

        var elems =  seed ||  multipleContexts( selector || "*" , context.nodeType ? [ context ] : context ,[]);

        var matcherIn = elems;

        var matcherOut = [];

        if ( matcher ) {

            matcher( matcherIn, matcherOut);

        }

        matcherOut = condense(matcherOut);

        if ( postFinder ) {

            postFinder( null, results, matcherOut );

        } else {

            push.apply( results, matcherOut );

        }

    })

}

// !addCombinator

// 增加关系处理函数

// 返回关系函数,主要功能是,遍历种子节点的关系节点。

// 比如li>a,传入无数个种子节点a,a.parentNode,再执行matcher,matcher里再判断这个父亲节点是不是li

function addCombinator( matcher, combinator ) {

    var dir = combinator.dir;

    return combinator.first ?

        function( elem, context ) {

            while( (elem = elem[ dir ]) ){

                if ( elem.nodeType === 1 ) {

                    return matcher( elem, context );

                }

            }

        }:

        function( elem, context ) {

            while ( (elem = elem[ dir ]) ) {

                if ( elem.nodeType === 1 ) {

                    if(matcher( elem, context )) {

                        return true;

                    }

                }

            }

            return false; 

        }

}



// !elementMatcher

// 生成matchers遍历器

// matchers数组存放我要过滤的函数,这个函数遍历所有过滤函数,一个不符合就返回false。

function elementMatcher( matchers ) {

    return function( elem, context ) {

        var i = matchers.length;

        while ( i-- ) {

            if ( !matchers[i]( elem, context ) ) {

                return false;

            }

        }

        return true;

    };

}

// !matcherFromTokens

// 根据tokens,生成过滤一组函数matchers,供elementMatcher使用

// 返回的是一个执行所有过滤函数的函数

function matcherFromTokens( tokens ){

            

    var matchers = [];

    var matcher;

    var type;

    var i = 0;

    var j ;

    var len = tokens.length;

    for ( ; i < len; i++ ) {

        if ( (matcher = Expr.relative[ tokens[i].type ]) ) {

            matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];

        } else {

            matcher = Expr.filter[ (type = tokens[i].type) ].apply( null, tokens[i].matches );

            if ( matcher[ expando ] ) {

                j = i+1;

                return setMatcher(

                    i > 0 && elementMatcher( matchers ),

                    i > 0 && toSelector( tokens.slice( 0, i ) ),

                    matcher,

                    j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),

                    j < len && toSelector( tokens )

                );

            }

            matchers.push( matcher );

        }

    }

    return elementMatcher( matchers );

}

// !matcherFromGroupMatchers

// 返回超级匹配器,

function matcherFromGroupMatchers( elementMatchers, setMatchers ){

    var bySet = setMatchers.length > 0,

        byElement = elementMatchers.length > 0;

    // !!最重要superMatcher,也是最核心的函数,其它的函数为它服务。

    // 获取种子元素,遍历所有种子元素。

    // 遍历elementMatchers

    // 符合的推入结果数组

    // 一个选择器(逗号隔开的)生成一个elementMatcher,elementMatchers是存放所有elementMatcher的数组

    var superMatcher = function( seed, context, results) {

        var elems = seed || Expr.find["TAG"]( "*", document );

        var len = elems.length

        var i = 0;

        var j;

        var unmatched = seed ? slice.call(seed, 0) : undefined ;

        var setMatched = [];

        for ( ; i !== len && (elem = elems[i]) != null; i++ ) {

            if( byElement ){

                j = 0;

                while ( (matcher = elementMatchers[j++]) ) {

                    if ( matcher( elem, context) ) {

                        results.push( elem );

                        break;

                    }

                }

                

            }

        }

        if ( bySet) {

            j = 0;

            while ( (matcher = setMatchers[j++]) ) {

                matcher( unmatched, setMatched, context);

            }

            push.apply( results, setMatched );

        }

        return unmatched;

    }

    return bySet ?

        markFunction( superMatcher ) :

        superMatcher;;

}

// compile

// 最初的编译器,存放elementMatchers,缓存超级匹配函数并返回

compile = Sizzle.compile = function( selector, match ) {

    var i;

    var elementMatchers = [];

    var setMatchers = [];

    var    cached = compilerCache[ selector + " "];    

    if ( !cached ) {

        if ( !match ) {

            match = tokenize( selector );

        }

        i = match.length;

        while ( i-- ) {

            cached = matcherFromTokens( match[i] );

            if ( cached[ expando ] ) {

                setMatchers.push( cached );

            } else {

                elementMatchers.push( cached );

            }

        }

        cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ));

    }

    return cached;

}

// select

// 兼容的自写的选择器

select = Sizzle.select = function( selector, context, results){

    var token;

    var seed;

    var tokens;

    var find;

    var match = tokenize( selector )

    if ( match.length === 1 ) {

        // tokens

        var tokens = match[0].slice( 0 );

        // 如果tokens的首项是ID,将其设置为上下文

        if ( (token = tokens[0]).type === 'ID' ){    

            context = document.getElementById(token.matches[0]);

            selector = selector.slice( tokens.shift().value.length );

        }

        // 生成种子seed

        // 如"div ul li",所谓种子就是所有的li

        // 后面编译函数需要过滤出符合祖先是ul,ul的祖先是div的节点

        // 在筛选选择中,如li:eq(0),不可以从左边直接取种子。

        i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;;

        while ( i-- ){

            token = tokens[i];

            if ( Expr.relative[ (type = token.type) ] ) {

                break;

            }

            if((find =  Expr.find[ type ]))

                if( seed = find( token.matches[0],context ) ) {

                    tokens.splice( i, 1 );

                    selector = toSelector( tokens )

                    break;

                }

        } 

    };

    // 根据selector,tokens(match防止对原tokens修改)生成superMatcher并调用

    compile( selector, match )( seed, context, results );

    return results;

}



// 对外入口

window.MSizzle = Sizzle;



})(window)

// 测试/*

console.log(MSizzle("a:not(.b)"))

console.log(Sizzle("a:not(.b)"))

1.整体的思路是,comple生成超级选择函数,这个函数主要用两种情况,一种是以前的elementMatcher,一种是setMatcher,用函数expando属性来区别执行哪条。本章的内容主要分析伪类筛选的基本筛选,大多数都是setMatcher路线,当然少数如:header,:root,:target则不是。

我们继续以一条路径来分析setMatcher路线,div:first,在setMatcher函数里,先根据前面的选择器执行Sizzle(’div‘),在这些div里进行基本筛选的first筛选。

2.markFunction,对函数进行标记并返回函数。Sizzle中根据选择器获取函数,如果有标记属性,则存入setMatchers。这是伪类路线,否则存入elementMatchers,一般路线。示例:

 1 var expando = "sizzle" + 1 * new Date();

 2 var filter = {

 3     'pseudos': markFunction(function(){

 4     

 5     }),

 6     'TAG': function(){

 7     

 8     }

 9 }

10 function markFunction(fn){

11     fn[expando] = true;

12     return fn;

13 }

14 function devider(selectorType){

15     if( filter[type][expando] ){

16         console.log('伪类路线')

17     }else{

18         console.log('基本路线')

19     }

20 }

21 devider('pseudos')
View Code

3.只要选择器中有走setMatchers路线的方法

你可能感兴趣的:(实现)