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好,即使看不懂也不会碰到隐藏的'宝藏'。

 

  完结撒花

  

原文地址:https://www.cnblogs.com/QH-Jimmy/p/6481874.html