jquery源碼分析-3:jQuery對象擴展-extend

寫過jquery插件的人都知道可以通過jquery提供的extend可以對jquery對象進行擴展,而且該方法不僅可以對jquery對象擴展,還能給一個對象添加新的屬性和方法,這個在後面會介紹。

通過不同的方式調用extend擴展的方法也不同:

  1. 通過 $.extend() 擴展的是靜態方法;

  2. 而通過 $.fn.extend() 擴展的是實例方法。

寫過jQuery插件的通過應該都知道,很多時候我們都是使用extend來為jQuery對象添加插件的。

;(function($){

$.fn.extend({

Firstplus: function() {}

});

//這樣寫的話插件的使用方法就是:$('div').Firstplus();

Advertisements

$.extend({

Secondplus: function() {}

});

//這樣寫的話插件的使用方法就是:$.Secondplus();

})($);

查看源碼的第285行,$.extend()和$.fn.extend()調用的其實是同一個函數,那麼他們實現的功能為什麼不同呢?

jQuery.extend = jQuery.fn.extend = function() {} //源碼285行

主要是因為這個方法都是將傳入的對象擴展到了this上。

  • $.extend( xx ) 的this指向的是jQuery對象,所以此時擴展的是jQuery對象,可以直接通過$.xx 的方式調用。

  • $.fn.extend( xx ) 的this指向的是jQuery對象的prototyep,所以此時擴展的jQuery對象的原型,實例化的jQuery對象可以調用所有的jQuyer原型上的方法,可以直接通過 $().xx 的方式調用。

    Advertisements

以下是extend的三種不同用法:

  1. 1. jQuery.extend( [ object ] )

    >將傳入的 object 擴展到 this 對象上

  2. 2. jQuery.extend( target, [ object1 ,... objectN ] )

    >將後面傳入的 object1 到 objectN 擴展到 target 對象上

  3. 3. jQuery.extend( [ deep ], target, [object1,... objectN ] )

    >如果傳入了 deep 參數表示遞歸後面傳入object1到objectN對象然後在擴展到target,這樣同名的屬性名就不會被覆蓋了。

具體看下源碼分析:

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

//定義了一些變數

var options, name, src, copy, copyIsArray, clone,

target = arguments[0] || {}, //target用來存儲傳入的第一個對象(目標對象)

//這個target不僅表示要進行合併的目標對象,也可以表示要擴展到jquery上的對象

i = 1, //i用來表示target後面傳入的對象是arguments的第幾個參數

length = arguments.length,

deep = false; //deep變數表示,是否進行深度拷貝

//先進行了一系列的if判斷,來初始化參數,判斷到底是要擴展jQuery還是對傳入的對象進行擴展

//如果第一個參數是布爾類型,則表示是否深度拷貝

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

deep = target;

target = arguments[1] || {}; //將目標對象置為傳入的第二個參數,如果沒有置為空對象

// skip the boolean and the target

i = 2; //將i置為2

}

//如果target不是一個對象,將其置為空對象

if ( typeof target !== "object" && !jQuery.isFunction(target) ) {

target = {};

}

//如果arguments和i相等,表示要擴展的jquery對象,讓target指向this

//這個this具體指向什麼之前已經探討過了

if ( length === i ) {

target = this;

--i; //且讓i--,這時arguments[i]表示的才是要擴展到jquery上的對象

}

for ( ; i < length; i++ ) { //開始遍歷傳入的 arguments

// 只有參數不為空時才執行後面的操作

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

// 對對象進行擴展,無論傳入的target對象,還是jQuery對象,都使用同樣的方法進行擴展

for ( name in options ) { //遍歷傳入的對象的屬性

src = target[ name ];

copy = options[ name ];

//防止target和obj的某個屬性指向的是同一對象進入死循環

if ( target === copy ) {

continue;

}

//是否進行深度拷貝

//這裡說的深度拷貝,和我們平時說的深度拷貝有點區別;這裡指的當obj的某個屬性是一個對象時,是否對這個屬性繼續遍歷,如果不進行遍歷的話,會直接覆蓋target對象的同名屬性

if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {

if ( copyIsArray ) { //如果要拷貝的obj屬性為數組

copyIsArray = false;

clone = src && jQuery.isArray(src) ? src : [];

} else { //如果要拷貝的obj屬性為對象

clone = src && jQuery.isPlainObject(src) ? src : {};

}

// 進行遞歸,直到屬性不再為一個對象或數組

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

} else if ( copy !== undefined ) {//如果不進行深拷貝且當前obj的屬性不為空

//擴展target對象,且和當前obj屬性名相同。

target[ name ] = copy;

}

}

}

}

return target; 最後返回target對象,如果擴展的jquery對象,則返回的就是jquery對象

};

通過extend函數,可以看出extend函數通過許多的 if 判斷,實現了許多不同的功能:

  • - 擴展多個對象到一個對象上;

  • - 擴展多個對象到一個對象上,並對要進行擴展的對象進行遍歷,防止將同屬性名的對象覆蓋;

  • - 擴展一個對象到jquery對象上;

  • - 擴展一個對象到jquery的原型對象上。

後面還可以看到 jq 通過這個方法擴展了很多工具方法到jQuery對象上,不得不說 jq 的結構還是很緊湊的,一個方法不僅提供給外部使用,在內部也多次使用,這不就是傳說中的高內聚么,看樣子看源碼對自己還是有很大的提升的,我是不是又漲見識,哈哈哈哈。

Advertisements

你可能會喜歡