• jQuery源码学习14——源码阅读总结


    先总结一下之前看jQuery源码的感受:

    由于没有看源码的经验,所以通常就是直接去看源码,然后感觉有些地方不知道为什么写成那样,现总结原因如下:

    1、由于自己工作经验积累的不够,看到某些细节的处理时不知道为什么那么做,例如判断一个变量是否为String类型,我发现jQuery源码内部进行了多次改造:

      jQuery1.0中是通过 a.constructor == String 这种方式来判断

      jQuery1.1是typeof a == "string"

      从jQuery1.3之后,虽然有细节上的差别,但是原理上都是通过 Object.prototype.toString.call(a) == "[object String]" 来判断的

      后来才知道前两种判断方法都是有缺陷的

    2、没有从全局上把握好,源码内部有些方法在好多地方都是调来调去,所有调用的地方都需要考虑到,例如刚开始看到Callbacks的时候,我做了一个非常简单的测试:

      var cb=$.Callbacks("memory");

      打了个断点跟着代码走一遍,但一开始就发现了一个奇怪的现象:

      我很天真的认为optionsCache是一个全局变量,初始为空对象,所以刚开始进去的时候optionsCache一定是一个空对象,然后optionsCache[options]自然是undefined,然后会调用createOptions函数,不过通过上面贴的这张图也看到了,事情并没有和我想的一样,在2835行即将执行的时候,optionsCache已经赋过值了,后来越想越不对劲,我明明第一次调用Callbacks,为什么全局变量optionsCache会有值,后来打了一个断点跟踪了一下,在堆栈中发现了一些端倪:

    于是大致猜出是怎么回事了:Callbacks为Deffered提供了基础,Deffered为ready.promise提供了基础,所以在我调用$.Callbacks()之前进入createOptions函数的情况就是预加载的时候进入的,在此之前看到过很多文章说jQuery中的Callbacks为Deffered Ajax 预加载提供了基础,但是分析到现在才知道这句话的真正含义

    还有一次是看到add和remove的源码时,这两个函数上来就判断list是否存在,这也让我感觉很纳闷,list是个全局变量,初始化成了数组,它一定存在啊,干嘛判断这个变量,但是往后看才发现,在$.Callbacks("once")的情况下,将add进去的函数执行完了之后再add的话是不允许add的,而第一次add完了之后会把list置为undefined,以此来达到再add的时候不让往进add的效果,为什么判断list是否存在也就不言而喻了

    3、某些地方简化了代码,很难理解作者的逻辑,例如init实例化方法中:字符串的情况结构如下:

        if(typeof selector === "string"){
            //个人认为这第一个if else是做了一些准备工作,这些准备工作是先把传入id和标签的情况拿了出来
            if(selector.charAt(0) === "<" && selector.charAt(selector.length - 1) === ">" && selector.length >= 3){
                match = [null, selector, null];
            }else{
                match = rquickExpr.exec(selector);
            }
            //个人认为这第二个if else是开始对传入的字符串做处理,这些处理不是仅限于处理上一个if else中match到的情况,因为上一个if else中match到的仅仅是id和标签这两种情况
            if(match && (match[1] || !context)){
                //处理match到的情况
                if(match[1]){
                    //处理传入html标签的情况,返回被解析成的DOM对象
                }else{
                    //处理传入id的情况
                }
            }else if(!context || content.jquery){
                //处理传入$(expr,context) 个人认为这种用法非常少
                return (context || rootjQuery).find(selector);
            }else{
                //处理传入$(expr)的情况 会进入Sizzle
                return this.constructor(context).find(selector);
            }
        }

    首先在第一个if else中,之所以先把id和标签的情况先通过match拿出来,个人感觉是因为这两种情况有其本身的特殊性

    事实上,当传入字符串时无非就是两种情况,当传入html标签时,是要创建DOM元素,除此之外的所有情况都是获取元素

    而获取元素中有一种特殊情况就是传入id的情况,由于id只能通过document.getElementById来获取这个元素,因此处理上反而简单了很多,不必再进入复杂的Sizzle

    因此,才单独把创建元素(传入html标签的情况)和获取唯一元素(传入id的情况)这两种情况单独拿了出来

    除此之外还有一个难以理解的地方就是第二个if else中的第一个if判断:if(match && (match[1] || !context))

    直到看了阿里巴巴的高云写的《jQuery技术内幕——深入理解jQuery架构设计与实现原理》之前,这句代码真是没有一点思路

    书中是这样解释的:这行代码用布尔表达式的计算顺序,省略了对match[2]的判断,完整的表达式如下:

    if(match && (match[1] || match[2] && !context))

  • 相关阅读:
    11.22
    11.19
    ConcurrentHashMap中sizeCtl的说明
    Spring源码解析(七) -- Spring事务-初始化篇
    Spring源码解析(六) -- AOP
    Spring源码解析(五) -- 解决循环依赖
    Spring源码解析(四) -- getBean(String name, Class<T> requiredType)
    Spring源码解析(三) -- registerBeanPostProcessors(beanFactory)
    Spring源码解析(二) -- invokeBeanFactoryPostProcessors
    Spring源码解析(一) -- beanfactory
  • 原文地址:https://www.cnblogs.com/zhaohuiziwo901/p/5016935.html
Copyright © 2020-2023  润新知