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大神!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM