jquery源碼分析-3:jQuery對象擴展-extend
寫過jquery插件的人都知道可以通過jquery提供的extend可以對jquery對象進行擴展,而且該方法不僅可以對jquery對象擴展,還能給一個對象添加新的屬性和方法,這個在後面會介紹。
通過不同的方式調用extend擴展的方法也不同:
通過 $.extend() 擴展的是靜態方法;
而通過 $.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. jQuery.extend( [ object ] )
>將傳入的 object 擴展到 this 對象上
2. jQuery.extend( target, [ object1 ,... objectN ] )
>將後面傳入的 object1 到 objectN 擴展到 target 對象上
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 的結構還是很緊湊的,一個方法不僅提供給外部使用,在內部也多次使用,這不就是傳說中的高內聚么,看樣子看源碼對自己還是有很大的提升的,我是不是又漲見識,哈哈哈哈。