• jQuery源码的一个坑


    纯吐槽

      大半夜也真是够了,想学着jQ造个小轮子巩固下js,结果一开始就卡住了。

      虽然之前也看过源码,但是主要是研究方法实现什么的,对于框架主函数和入口结构不怎么熟悉,于是想着一步一步调试看看。

    $('#div')

      简单吧,为了方便调试看过程,直接调用选择符,而且是一个ID,可以快速匹配调用原生方法。

      大概流程是这样的。

        var
            version = "3.1.1",
    
            // Define a local copy of jQuery
            jQuery = function(selector, context) {
    
                // The jQuery object is actually just the init constructor 'enhanced'
                // Need init if jQuery is called (just allow error to be thrown if not included)
                return new jQuery.fn.init(selector, context);
            },

      首先,如我所料进入了主函数,然后调用了new准备构造出一个对象(目的是为了应对奇怪的参数导致错误)。

        //一号坑 没注意到缩写
        init = jQuery.fn.init = function(selector, context, root) {
            var match, elem;
    
            // HANDLE: $(""), $(null), $(undefined), $(false)
            if (!selector) {
                return this;
            }
            //...
        }

      然后,进入了初始化函数,jQ有很多地方多缩写了,比如说jQuery.fn=jQuery.prototype,这里也缩写,当时没注意。

      一般情况会进入Sizzle引擎,但是因为用的ID,比较简单,提前返回。返回的是一个'jQuery'对象,里面包含一个DOM节点,原型有大量的方法。(这里一定要加上引号)

      好,开始学着造轮子。

        //入口函数
        var jimmy = function(ele) {
            return new jimmy.prototype.init(ele);
        };
    
        //是要简化一下
        jimmy.fn = jimmy.prototype;
    
        //超简单扩展函数
        jimmy.fn.extend = function(o1, o2) {
            for (var key in o1) {
                this[key] = o1[key];
            }
            return this;
        };
    
        //初始化
        jimmy.fn.init = function(ele, ctx) {
            ele = rquickExpr.exec(ele);
            return this;
        }

      其中有段代码大概是这样子,反正我又不做兼容,问题出现了!我的jimmy对象原型,啥方法都没有,准备用来扩展的extend也没有。

      我就照着之前的调试又跑了一遍,还在函数中添加了多个console.log。结果发现jQuery源码在进入初始化函数中,this指向的是jQuery.init.prototype,这个理论上是没问题的,毕竟new出一个对象,默认就是这样的,接着函数中直接返回了this。

      对着控制台我就看到了这个jQuery对象是这个样子的,jQuery.fn.init[1]。WTK!说好的jQuery对象呢?怎么是jQuery原型的初始化对象?我可能初始化了一个假的jQuery对象。。。接着点开了__proto__属性,刷的一下方法就出来了。这???也就是说方法是定义在jQuery.fn.init.__proto__上的。

      回头又翻了下jQuery的扩展函数extend,发现貌似是普通的拷贝,并没有对this做特殊处理。也就是说,原型方法还是在jQuery原型上。那为什么方法怎么跑到jQuery原型方法的原型上的???

      我一行一行的看代码,直到我发现这么一条语句。

        // Give the init function the jQuery prototype for later instantiation
        init.prototype = jQuery.fn;

      恩,对的,在后面代码的某一行中,出现了这么一条语句,就像两个高手进行结拜一样,这两玩意的原形应该是这样的。

        jQuery.prototype.init.prototype = jQuery.prototype

      这条语句确实挺恶心的,但是更恶心的是放源码中间,还加了一句注释:将jQuery原型给init函数方便后面初始化。

      后面你妹啊!初始化语句全在前面好不!恩,好吧,英文博大精深,应该是说方便jQuery之后执行初始化。

      总之,我一晚上的时间都献给了这句代码,虽然弄明白了初始化,但是总感觉被作者耍了,还是尤大的vue好,即使看不懂也不会碰到隐藏的'宝藏'。

     

      完结撒花

      

  • 相关阅读:
    ImportError: cannot import name 'render_to_response' 解决方法
    python 操作zookeeper详解
    Appium swipe实现屏幕滑动
    Appium 环境配置
    pytest 常用方法介绍
    Allure+pytest 生成测试报告
    Pytest 使用简介
    python 实现线程之间的通信
    python 使用 thrift 教程
    nginx 配置简单反向代理
  • 原文地址:https://www.cnblogs.com/QH-Jimmy/p/6481874.html
Copyright © 2020-2023  润新知