JQuery源碼解析(一)

寫在前面:本<JQuery源碼解析>系列是基於一些前輩們的文章進行進一步的分析、細化、修改而寫出來的,在這邊感謝那些慷慨提供科普文檔的技術大拿們。javascript

要查閱JQ的源文件請下載開發版的JQ.js文檔,下載地址:http://jquery.com/download/ 注意選擇其中的development版本進行下載,以下圖所示java

開發版本的JQ.js屬於非壓縮的源文件,方便咱們閱讀和分析其代碼。 下載完用Dreamweaver或其它代碼編輯器打開查閱便可。咱們從此分析的代碼也是基於1.11.0版本的JQ源代碼。node

 

 

第一眼看JQ的源代碼或許會感到混亂和沒頭緒,特別是會卡在36行的代碼那裏遲遲找不到「function( window, noGlobal ) {」的後半段終點:jquery

// Pass this if window is not defined yet
}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {      /* 很容易看卡在這裏,不知道function( window, noGlobal )到哪裏才結束 */

 不過如今能夠直接告訴你,function( window, noGlobal )可謂是貫穿後面代碼的所有部分,屬於JQ整體架構的一部分。JQ的主體代碼以下:瀏覽器

(function( global, factory ) {

    if ( typeof module === "object" && typeof module.exports === "object" ) {
        // For CommonJS and CommonJS-like environments where a proper window is present,
        // execute the factory and get jQuery
        // For environments that do not inherently posses a window with a document
        // (such as Node.js), expose a jQuery-making factory as module.exports
        // This accentuates the need for the creation of a real window
        // e.g. var jQuery = require("jquery")(window);
        // See ticket #14549 for more info
        module.exports = global.document ?
            factory( global, true ) :
            function( w ) {
                if ( !w.document ) {
                    throw new Error( "jQuery requires a window with a document" );
                }
                return factory( w );
            };
    } else {
        factory( global );
    }

// Pass this if window is not defined yet
}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {  /* 剛剛說的容易看卡住的地方 */

    //說白了這裏就是寫各類JQ功能函數的地方,大概有一萬多行

}));

 咱們把上面這個主架構函數再簡化成這樣:架構

(function( global, factory ) {
    .....
}(參數1,參數2));    //參數1就是那個「typeof window !== "undefined" ? window : this」,參數2就是那個「function( window, noGlobal ){..這裏有一萬多行哦..}」

 這種函數形式咱們稱之爲匿名函數,也就是沒有函數名的函數。介紹匿名函數以前咱們先來看看函數的定義方式有哪些:框架

 

第一種,也是常規的一種:編輯器

function abc(x){
    alert (2 * x);   
}

 第二種:這種方法使用了Function構造函數,把參數列表和函數體都做爲字符串,很不方便,不建議使用:函數

var abc = new Function('x', 'alert (2 * x);');

第三種:等號右側先定義好函數,再賦給等號左側的變量。ui

var abc = function(x) { alert( 2* x ) ; }

這裏你須要知道的一點是,等號右邊的函數,就是匿名函數了。咱們能夠用一個變量指向它,並稱此變量爲該函數的「函數字面量」(注意不是函數名字,匿名函數的不會偶函數名的),像var aa=function(x) { alert( 2* x ) ; } ,則「aa」就是該函數的函數字面量。咱們能夠經過 aa(實參) 來執行該函數。

 

匿名函數還有另外一種定義形式:

(function(x){
    alert(2* x);  
})(3);

/* 也能夠寫作
(function(x){
    alert(2* x);  
}(3));
*/

 這種形式的函數沒有函數名,卻有調用參數的專屬括號(像上面的是「(3)」,表示把3做爲參數來強制調用賦值給x,最終alert出6)。

須要知道的是,像

(function(參數){...;}(調用參數));    //「參數」和「調用參數」都是無關緊要、數量可變的

這種形式的匿名函數,都是會當即執行的,無須寫什麼調用函數的代碼就會自動執行。你大能夠寫個頁面文件,加上

<script language="javascript">
(function(x){
    alert( 1+x );
})(2);
</script>

 而後運行該頁面,馬上會彈出「3」的窗口。

 

 

瞭解了匿名函數,那麼咱們回看JQ源碼:

可見JQ源碼就是一個匿名函數

1 (function( global, factory ) {
2 
3     ... //這裏是爲了兼容nodejs等一些其它的js框架;
4 
5 }(a,b))

其中形參global的實參a是一個三目運算符   typeof window !== "undefined" ? window : this    用於判斷當前執行環境是否支持window類型,是的話返回window,不然返回this

形參factory的實參b則是一個函數,裏面包含了一萬多行的JQ功能函數  function( window, noGlobal ) { ......  }

既然這個外部匿名函數的參數的值咱們都清楚了,那麼來看下這個匿名函數又是啥做用的?(光看JQ自帶的英文註釋咱們能夠大體知道它是爲了兼容node.js、sea-JS等符合CommonJS規範或類CommonJS規範的js框架)

首先咱們看這行判斷語句:      if ( typeof module === "object" && typeof module.exports === "object" )

玩過node.js的朋友天然會知道module.export和export是node.js中用來建立模塊的方法,那麼就好理解了,若此條件成立,則要執行下面語句來兼容node.js(說白了就是利用形參factory作中間人,來把JQ的各個功能模塊用node.js建立模塊的方法建立起來)

 {
            module.exports = global.document ?       //三目運算符,先判斷當前環境是否支持window.document屬性 
						     //(注意咱們上面提到過形參global的實參是window)

            factory( global, true ) :            //支持的話就好辦啦,只要咱用常規的瀏覽器通常都是支持的,那就直接module.exports = factory( global, true ),

					//把JQ後面那一萬多行的功能函數擴展到node.js裏面。(注意咱們上面提到過形參factory的實參是實現JQ各類功能的一個外部函數)

            function( w ) {			 //若是當前環境不支持window.document屬性,那就寫個函數扔個Error說這環境不適用JQ,但依舊返回JQ的功能函數(但大部分估計是不能用的了)
                if ( !w.document ) {

                    throw new Error( "jQuery requires a window with a document" );

                }

                return factory( w );

            };
}

 

 嗯,這樣就兼容了node.js咯,那麼若是咱沒有用node.js這種CommonJS規範的框架,也就是說條件if ( typeof module === "object" && typeof module.exports === "object" )不成立。那就直接執行後面else裏的部分:

factory( global );

也就是直接引入JQ那一萬多行的功能函數便可。

話說也寫了很多字,第一部分先到這裏吧 :)

donate

相關文章
相關標籤/搜索