• Sizzle之tokenize


    在Sizzle里,大体思路,当为复合选择器时,判断是否支持querySeletorAll,如果不支持则调用自写方法select。

    select的功能十分冗长,下面先分析tokenize

    在tokenize函数的作用是将形如'ul.topnav > li,div'的选择器解析为

    [
        [{value:'ul',type:"TAG",matches:['ul']},{value:'.topnav',type:"CLASS",matches:['topnav']},{value:' > ',type:">"},{value:'li',type:"TAG",matches:['li']}],
        [{value:'div',type:"TAG",matches:['div']}]
    ]

    每个逗号解析为一个数组,表示一个独立选择器项,每个独立选择器项的选择关系按照CLASS,TAG,ID和关系解析成如上格式。

    这种解析的类型是下面进行查找元素的固定格式,先不考虑后面,我们先分析tokenize的实现。

    //缓存函数创建函数
    var createCache = function(){
        //缓存函数共用数组
        var keys = [];
        return function cache(name,value){
            // 当长度大于某常数时,清除老元素,插入新元素
            if( keys.push( name ) > 1){
                delete cache[ keys.shift() ]
            };
            return cache[name] = value;
        };
    }
    //缓存函数对象
    //这是一个方法,通过这个方法可以将缓存数据保存在这个函数(也是对象)里。
    var tokenCache = createCache();
    //简易正则过滤对象
    var filter = {
        TAG: /^(w+)/,
        ID: /^#(w+)/,
        CLASS: /^.(w+)/
    }
    //关系匹配正则
    var relation = /^s*([>+~]|^s)s*/;
    //逗号正则
    var comma = /^\,/;
    function tokenize(selector){
        var cached = tokenCache[selector];
        //缓存中有结果,直接返回
        if(cached){
            return cached;
        }
        // 循环条件
        var sofar = selector,
        // 结果数组
        groups = [],
        // 匹配参数
        matched,
        // 一个独立选择器项
        token = [],
        //辅助参数正则匹配结果
        match;
        //循环解析选择器
        while(sofar){
            //首次默认创建一个单独选择器项
            //之后通过判断逗号创建
            if(!matched || (match = comma.exec(sofar)) ){
                if(match){
                    //保存未解析的选择器
                    sofar = sofar.slice(match[0].length);
                }
                groups.push(token = []);
            }
            //每次循环设置辅助匹配参数为false,如果之后仍无匹配不存在通过break跳出循环
            matched = false;
            //匹配关系>等
            //解析保存结果
            if(match = relation.exec(sofar)){
                matched = match.shift();
                token.push({
                    value: matched,
                    type: match[0].replace( /s+/g, " " )
                })
                sofar = sofar.slice(matched.length)
            }
            //匹配选择器CLASS,TAG,ID
            //解析保存结果
            for(var type in filter){
                if(match = filter[type].exec(sofar)){
                    matched = match.shift();
                    token.push({
                        value: matched,
                        type: type,
                        matches: match
                    })
                    sofar = sofar.slice(matched.length)
                }
            }
            //没有跳出循环。
            if ( !matched ) {
                break;
            }
        
        }
        //缓存结果并返回
        return (tokenCache(selector,groups));
    }
    console.log(tokenize('ul.topnav > li,div'))
    console.log(tokenize('a li'))

    这是我模拟输入输出结果写出的函数,jQuery源码中在实现主要功能的基础上进行了大量兼容处理。

    缓存在jQuery里面非常常用,在这里重新说一遍基本思路是,将函数输入值key,和输出值保存于缓存对象中,等到下次调用函数,如果缓存对象中有值,则直接读取。

    本例的缓存略微复杂,它是利用函数将缓存数据保存于同名对象中。又,作者希望几种缓存共用长度,在这里用了创建缓存函数的函数。

  • 相关阅读:
    计算机网络中的码元的理解
    屏幕扩展,屏幕相对位置的设置
    wireshark使用入门
    Http下载文件的登录验证
    正则-连续相同的单词
    文件系统和数据库索引用B树而不是红黑树的原因
    红黑树的突破点
    Win 10 Revit 2019 安装过程,亲自踩的一遍坑,有你想要的细节
    Java拦截器的实现原理
    根据进程数,资源数判断是否发生死锁
  • 原文地址:https://www.cnblogs.com/winderby/p/4178065.html
Copyright © 2020-2023  润新知