天天看點

【轉】jQuery源碼分析-03構造jQuery對象-源碼結構和核心函數

前記:

想系統的好好寫寫,但是會先從感興趣的部分開始。

近期有讀者把pdf傳到了百度文庫上,首先感謝轉載和傳播,但是據為已有并設定了挺高的财富值才能下載下傳就不好了,以後我整理好了會傳到文庫上。請體諒一下。

3. 構造jquery對象

先看看總體結構,再做分解:

<col>

(function( window, undefined ) {

    var jquery = (function() {

       // 建構jquery對象

       var jquery = function( selector, context ) {

           return new jquery.fn.init( selector, context, rootjquery );

       }

       // jquery對象原型

       jquery.fn = jquery.prototype = {

           constructor: jquery,

           init: function( selector, context, rootjquery ) {

              // selector有以下7種分支情況:

              // dom元素

              // body(優化)

              // 字元串:html标簽、html字元串、#id、選擇器表達式

              // 函數(作為ready回調函數)

              // 最後傳回僞數組

           }

       };

       // give the init function the jquery prototype for later instantiation

       jquery.fn.init.prototype = jquery.fn;

       // 合并内容到第一個參數中,後續大部分功能都通過該函數擴充

       // 通過jquery.fn.extend擴充的函數,大部分都會調用通過jquery.extend擴充的同名函數

       jquery.extend = jquery.fn.extend = function() {};

       // 在jquery上擴充靜态方法

       jquery.extend({

           // ready bindready

           // isplainobject isemptyobject

           // parsejson parsexml

           // globaleval

           // each makearray inarray merge grep map

           // proxy

           // access

           // uamatch

           // sub

           // browser

       });

        // 到這裡,jquery對象構造完成,後邊的代碼都是對jquery或jquery對象的擴充

       return jquery;

    })();

    window.jquery = window.$ = jquery;

})(window);

l jquery對象不是通過 new jquery 建立的,而是通過 new jquery.fn.init 建立的

var jquery = function( selector, context ) {

       return new jquery.fn.init( selector, context, rootjquery );

}

n  jquery對象就是jquery.fn.init對象

n  如果執行new jqeury(),生成的jquery對象會被抛棄,最後傳回 jquery.fn.init對象;是以可以直接調用jquery( selector, context ),沒有必要使用new關鍵字

l  先執行 jquery.fn = jquery.prototype,再執行 jquery.fn.init.prototype = jquery.fn,合并後的代碼如下:

jquery.fn.init.prototype = jquery.fn = jquery.prototype

所有挂載到jquery.fn的方法,相當于挂載到了jquery.prototype,即挂載到了jquery 函數上(一開始的 jquery = function( selector, context ) ),但是最後都相當于挂載到了jquery.fn.init.prototype,即相當于挂載到了一開始的jquery 函數傳回的對象上,即挂載到了我們最終使用的jquery對象上。

這個過程非常的繞,金玉其外“敗絮”其中啊!

jquery.fn.init的功能是對傳進來的selector參數進行分析,進行各種不同的處理,然後生成jquery對象。

類型(selector)

處理方式

dom元素

包裝成jquery對象,直接傳回

body(優化)

從document.body讀取

單獨的html标簽

document.createelement

html字元串

document.createdocumentfragment

#id

document.getelementbyid

選擇器表達式

$(…).find

函數

注冊到dom ready的回調函數

// 合并兩個或更多對象的屬性到第一個對象中,jquery後續的大部分功能都通過該函數擴充

// 通過jquery.fn.extend擴充的函數,大部分都會調用通過jquery.extend擴充的同名函數

// 如果傳入兩個或多個對象,所有對象的屬性會被添加到第一個對象target

// 如果隻傳入一個對象,則将對象的屬性添加到jquery對象中。

// 用這種方式,我們可以為jquery命名空間增加新的方法。可以用于編寫jquery插件。

// 如果不想改變傳入的對象,可以傳入一個空對象:$.extend({}, object1, object2);

// 預設合并操作是不疊代的,即便target的某個屬性是對象或屬性,也會被完全覆寫而不是合并

// 第一個參數是true,則會疊代合并

// 從object原型繼承的屬性會被拷貝

// undefined值不會被拷貝

// 因為性能原因,javascript自帶類型的屬性不會合并

// jquery.extend( target, [ object1 ], [ objectn ] )

// jquery.extend( [ deep ], target, object1, [ objectn ] )

jquery.extend = jquery.fn.extend = function() {

    var options, name, src, copy, copyisarray, clone,

       target = arguments[0] || {},

       i = 1,

       length = arguments.length,

       deep = false;

    // handle a deep copy situation

    // 如果第一個參數是boolean型,可能是深度拷貝

    if ( typeof target === "boolean" ) {

       deep = target;

       target = arguments[1] || {};

       // skip the boolean and the target

       // 跳過boolean和target,從第3個開始

       i = 2;

    }

    // handle case when target is a string or something (possible in deep copy)

    // target不是對象也不是函數,則強制設定為空對象

    if ( typeof target !== "object" &amp;&amp; !jquery.isfunction(target) ) {

       target = {};

    // extend jquery itself if only one argument is passed

    // 如果隻傳入一個參數,則認為是對jquery擴充

    if ( length === i ) {

       target = this;

       --i;

    for ( ; i &lt; length; i++ ) {

       // only deal with non-null/undefined values

       // 隻處理非空參數

       if ( (options = arguments[ i ]) != null ) {

           // extend the base object

           for ( name in options ) {

              src = target[ name ];

              copy = options[ name ];

              // prevent never-ending loop

              // 避免循環引用

              if ( target === copy ) {

                  continue;

              }

              // recurse if we're merging plain objects or arrays

              // 深度拷貝且值是純對象或數組,則遞歸

              if ( deep &amp;&amp; copy &amp;&amp; ( jquery.isplainobject(copy) || (copyisarray = jquery.isarray(copy)) ) ) {

                  // 如果copy是數組

                  if ( copyisarray ) {

                     copyisarray = false;

                     // clone為src的修正值

                     clone = src &amp;&amp; jquery.isarray(src) ? src : [];

                  // 如果copy的是對象

                  } else {

                     clone = src &amp;&amp; jquery.isplainobject(src) ? src : {};

                  }

                  // never move original objects, clone them

                  // 遞歸調用jquery.extend

                  target[ name ] = jquery.extend( deep, clone, copy );

              // don't bring in undefined values

              // 不能拷貝空值

              } else if ( copy !== undefined ) {

                  target[ name ] = copy;

    // return the modified object

    // 傳回更改後的對象

    return target;

};

未完待續

from:http://nuysoft.iteye.com/blog/1182087

繼續閱讀