jquery-extend源碼分析

PS:此次分析基於2.0以上版本;jquery

jquery的extend你們都不陌生,也是jquery的重要接口,寫過jquery組件的人都用過extend吧!ajax

先說兩個$.extend()和$.fn.extend();json

當只寫一個對象自變量的時候,是Jquery中擴展插件的形式;$.extend() ->$.ajax;數組

而$.fn.extend是擴展Jquery實例方法; $.fn.extend ->$().方法;函數

接下來看下extend的源碼,首先在jquery中定義了一些變量:oop

var src, copyIsArray, copy, name, options, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;   //是不是深拷貝this

將目標定爲第一個參數,正常狀況下目標元素是個對象,固然後面jquery會作處理;prototype

if ( typeof target === "boolean" ) { 
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
}插件

在第一個判斷中,會判斷目標對象是不是布爾值,若是是,說明是深拷貝,將目標元素設爲第二個參數;對象

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

這個時候已經肯定目標對象是對象了,如今判斷目標對象不是對象或者函數的時候,將目標對象轉換爲對象;

if ( length === i ) {
target = this;
--i;
}

接下來的這個判斷是判斷是否是插件形式,若是隻寫一個對象,把這個對象擴展到jquery源碼上,只要判斷length和i是否相等。若是相等的活,把target設爲this,this可能爲兩種狀況,$或者$.prototype.

for ( ; i < 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 && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];

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

// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );

// Don't bring in undefined values
} else if ( copy !== undefined ) { 
target[ name ] = copy;
}
}
}
}

這個for循環是處理對個對象的狀況,若是有多個對象,多個對象都要擴展到第一個對象上面。for循環中的if以下

if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];

首先判斷參數是否有值,而後把各類賦值。接下來以下:

if ( target === copy ) { 
continue;
}

這個if是判斷是防止循環引用的,如:

$.extend(x,{name : x}),若是不作上面那個if判斷,若是寫成這樣會形成循環引用。

接下來會開始判斷深度拷貝仍是淺拷貝

f ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];

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

// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );

// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}

首先經過deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) )判斷;deep -> 深淺拷貝  copy ->是不是對象或者數組

不知足以上條件就是淺拷貝。

if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];

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

這個判斷是拷貝數組和json不一樣狀況的不一樣處理。

若是src只寫src={}/ src=[];不寫src && jQuery.isPlainObject(src) ? src : {}/src : [];

這樣寫若是在多個對象繼承的時候,若是對象a和對象b有相同名字的屬性,就會把a原有的屬性給覆蓋,經過jquery的處理,就不會覆蓋之前的屬性。

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

在深拷貝中其實就是利用遞歸,針對不一樣狀況,分別處理。

相關文章
相關標籤/搜索