jquery源码学习 最小系统

先看看他的框架吧,了解了jquery的最小系统最小框架,大家等下就发现,他其实什么都没有做,这个就只是一个初始的骨架而已,当然,了解一下,对于我们应用他,还有扩展他应该是有所助益的.

另,本人js纯菜鸟一枚,生怕误导了和我一样的菜鸟阶级朋友,所以请大家在看的同时多动手,呵呵,也希望路过的大牛们顺手指正.非常感谢.

最小框架

(function(window, undefined) {

    var 
    rootjQuery,
    core_version = "1.9.1",

	_jQuery = window.jQuery,
	_$ = window.$,

	jQuery = function(selector, context) {
	    return new jQuery.fn.init(selector, context, rootjQuery);
	};

    jQuery.fn = jQuery.prototype = {
        jquery: core_version,
        constructor: jQuery,
        init: function(selector, context, rootjQuery) {
            return this;
        }
    };

    jQuery.fn.init.prototype = jQuery.fn;

    jQuery.extend = jQuery.fn.extend = function(dest, src) {
        for (var p in src) {
            dest[p] = src[p];
        }
        return dest;
    }

    jQuery.extend(jQuery, {
        noConflict: function(deep) {
            if (window.$ === jQuery) {
                window.$ = _$;
            }

            if (deep && window.jQuery === jQuery) {
                window.jQuery = _jQuery;
            }

            return jQuery;
        }
    });

    jQuery.extend(jQuery.fn, {
        method1: function(msg) {
            alert(msg);
            return this;
        }
        ,method2: function(msg) {
            alert(msg);
            return this;
        }
    });

    window.jQuery = window.$ = jQuery;

})(window);

jQuery.extend这个方法被我简写了,仅仅为了最小系统少几行代码,显得稍微清晰点而已.

调用示例

$().method1("Hello").method2("World!");

链式调用风格,很方便的.

如何扩展它?

(function(jQuery, undefined) {
    jQuery.fn.extend(jQuery.fn, {
        method3: function(msg) {
            alert("method2:" + msg);
            return this;
        }
    });
})(jQuery)

经过这么扩展,我们就有method3这个新的方法了,和method1等方法的调用什么都是一样的.

他是如何工作的?

首先,所有的工作都是在一个函数里面完成的(不包括扩展的部分),这是一个自运行函数,如果您对什么是自运行函数不太了解,可以参考一下函数声明,函数表达式等的资料.

先附上带代码注释吧,错漏的地方肯定不少,请大家批评指正.

/*!
* jQuery 最小系统
* Date: 2013-04-25
*/

//一个自运行的函数.
(function(window, undefined) {

    var 

    //到jQuery(document)的一个引用,所有的jquery对象都将引用到他
    rootjQuery,

    //定义自己的版本号
    core_version = "1.9.1",

    //通过局部变量保存可能会被覆盖的window属性
    //如果用户调用jQuery.noConflict(deep)方法
    //则会恢复window.jQuery和window.$的值
    //目的是为了和别人和平共处互不冲突
	_jQuery = window.jQuery,
	_$ = window.$,

    //我个人的理解是按jQuery().m1().m2()这种调用方式导致这么处理?
    //这意味着jQuery()返回的对象与m1,m2应该有相同的prototype?this?
    //从而,假设返回的是new init()
    //那么init.prototype===jQuery.prototype    
    //那么...
	jQuery = function(selector, context) { 
        //注释掉的这个有什么区别,有什么不妥吗?
        //如果使用了new的话,那么init函数中即使不return this应该也是可以的.
        //可见,new是在背后做了一些额外工作的
        //详情在本文的后面有说明
        //不过,刚查看到有人说了,这里用new,还有个隔离作用域的作用,表示不怎么明白,回去思考去,呵呵
        //关于这个隔离作用域,在文章后面有说明.
        //很多不该有的注释保留,是因为这个记录了本人的思考过程,嗯,由完全不明白,到明白一些些了,呵呵
        //return jQuery.fn.init(selector, context, rootjQuery);        
	    return new jQuery.fn.init(selector, context, rootjQuery);
	}; 
	
    jQuery.fn = jQuery.prototype = {
        jquery: core_version,
        constructor: jQuery,//注释掉的话,有什么后果?在本例中倒是没什么
        init: function(selector, context, rootjQuery) {
            return this;
        }
    };
    //要让jquery()能复用jquery.fn的属性?
    jQuery.fn.init.prototype = jQuery.fn;

    //扩展对象,这个已经简化了,所以他的调用方式也就面目全非了
    jQuery.extend = jQuery.fn.extend = function(dest, src) {
        for (var p in src) {
            dest[p] = src[p];
        }
        return dest;
    }

    jQuery.extend(jQuery, {
        //避免冲突
        noConflict: function(deep) {
            if (window.$ === jQuery) {
                window.$ = _$;
            }

            if (deep && window.jQuery === jQuery) {
                window.jQuery = _jQuery;
            }
            return jQuery;
        }
    });

    jQuery.extend(jQuery.fn, {
        //定义自己的方法,没啥用
        method1: function(msg) {
            alert("method1:" + msg);
            //都记得要返回,从而实现链式调用
            return this;
        }
        , method2: function(msg) {
            alert("method2:" + msg);
            return this;
        }
    });

    //最顶级的jquery对象,所有其他jquery都将引用到他
    rootjQuery = jQuery(document);

    //不管这两属性是否会冲突,用了再说
    //等用户自己调用noConflict吧,如果冲突的话
    window.jQuery = window.$ = jQuery;

})(window);

  

补充一点,本人一直迷糊的地方,就是,看看一个对象是如何new出来的?

最好当然是看ECMA文档了,下面的这个请在FF,Chrome下测试哦,IE就自动忽略吧.

var JSEngine = function(fn) {
    var This = this;
    this.constructor = fn;

    //伪代码
    this.newObject = function() {
        var 
        o = {}//创建一个原生对象
        , _constructor = This.constructor;

        //查看构造函数的prototype类型是否为object
        //是则将对象的内部属性Prototype应用到它
        //否则此属性指向Object.prototype
        if (typeof _constructor.prototype === "object") {
            o.__proto__ = _constructor.prototype;
        }
        else {
            o.__proto__ = Object.prototype; //{}?
        }

        //调用构造函数
        var o2 = _constructor.apply(o, arguments);
        //如果返回的是对象,则返回这个o2,否则返回o
        if (typeof o2 === "object") {
            return o2;
        }
        else { return o; }
    }
}

从上面的代码可以看出,当使用new构建一个对象的时候,总是会返回一个object,这也是为什么前面使用:

return new jQuery.fn.init(selector, context, rootjQuery);而不是return jQuery.fn.init(selector, context, rootjQuery);

的原因(我个人猜想的啊,主要是我没有看出有别的不妥的地方,请过路的大牛指点啊!!!后来才明白,其实应该是后面说道的隔离作用域的原因啊)

补充,刚从有些资料上看到,说此处用new是为了隔离作用域,哎,还得学习啊!!!

测试代码如下:

function fn1() {
    this.name = "AAA";
}

var js = new JSEngine(fn1);
var o1 = js.newObject();
var o2 = new fn1();
alert(o1.name); //AAA
alert(o2.name); //AAA
alert(o1 instanceof fn1); //true
alert(o2 instanceof fn1); //true

那么,正常的函数调用会是什么样子呢?正常的函数调用的话看看下面的伪代码:

function callFunction(fn, caller) {
    caller = caller || window;
    fn.apply(caller);
}

 这里的caller与arguments.callee.caller是两码事.

   由上面的伪代码看出,fn函数体内部的this,指向的就是caller. 那么,这个caller是什么?就是函数的调用者,常见有如下形式:

fn();//caller 默认就是全局对象
x.y.fn();//caller就是x.y

其实一般的场景都是这么简单的.那么,我们应该能够理解内部构造函数jQuery内部为什么是:

return new jQuery.fn.init(selector, context, rootjQuery);

而非

return jQuery.fn.init(selector, context, rootjQuery);

了吧? 前者得到的都是一个全新的对象(那么,作用域隔离的目的).后者的话,在init内部return this的话,总是得到同一个对象,那就是jQuery.fn, 这个意味着$()在任何地方都得到了一个唯一的相同的对象,这个就不能实现我们的目标了.

强烈推荐大家看《深入理解JavaScript系列》

最后,感谢John大神!!!

 

posted @ 2013-04-25 20:03  相忘于江湖  阅读(1834)  评论(4编辑  收藏  举报