一、jQuery.extend方法
1、用途
jQuery.extend方法是將多個對象(提供對象)的屬性(包括原型中的屬性)復制給另一個對象(要擴展的目標對象),使目標對象增強行為;當提供對象有而目標對象沒有的屬性(包括方法),則直接復制給目標對象,
當它們有相同的屬性名(即key鍵相同),且值為對象,設置參數deep = true時,數組和簡單對象會遞歸合並,否則直接覆蓋,不會合並。
2、用法
jQuery.extend( target, [ object1 ], [ objectN ] )
target 一個對象,如果附加的對象被傳遞給這個方法那么它將接收新的屬性,如果它是唯一的參數將擴展jQuery的命名空間
object1 一個對象,它包含額外的屬性合並到第一個參數
objectN 包含額外的屬性合並到第一個參數
jQuery.extend( [ deep ], target, object1, [ objectN ] )
deep 如果是true,合並成為遞歸(又叫做深拷貝)。
target 對象擴展。這將接收新的屬性。
object1 一個對象,它包含額外的屬性合並到第一個參數
objectN 包含額外的屬性合並到第一個參數
3、源碼解析

// 源碼解析 update-time:2014/05/20 (function( window, undefined ) { var jQuery = function() { // ... }; jQuery.extend = function() { // 提供合並的對象,提供合並對象的屬性,目標對象的屬性值,提供合並對象的屬性值 // 布爾值(判斷提供的合並對象屬性值類型是否為數組),遞歸中的目標對象(目標對象的屬性),目標對象 var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false; // 處理第一個參數為boolean類型 if ( typeof target === "boolean" ) { deep = target; target = arguments[1] || {}; // 略過第一個boolean類型參數和目標擴展對象,提供合並屬性的對象從第三個參數開始 i = 2; } // 目標參數類型不是對象、函數,則重置為一個新的空對象 if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } // 當參數只有一個,擴展jQuery本身( this指向jQuery ) if ( length === i ) { target = this; // 提供合並屬性的對象從第一個參數開始 --i; } // 枚舉提供合並的對象 for ( ; i < length; i++ ) { // 提供合並的對象不為null,注意這里比較的是值,不包括null類型 if ( (options = arguments[ i ]) != null ) { // 枚舉提供合並對象的屬性 for ( name in options ) { src = target[ name ]; copy = options[ name ]; // 當目標對象與被復制屬性值指向同一引用,則跳出本次循環 if ( target === copy ) { continue; } // 被復制屬性值的類型為對象、數組 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { // 指定遞歸中要擴展的目標為數組 if ( copyIsArray ) { copyIsArray = false; // 需要重置為false,因為jQuery.isPlainObject(copy)為true時,始終都是執行第一個if語句 clone = src && jQuery.isArray(src) ? src : []; } // 指定遞歸中要擴展的目標為對象 else { clone = src && jQuery.isPlainObject(src) ? src : {}; } // 使用jQuery.extend方法進行遞歸 target[ name ] = jQuery.extend( deep, clone, copy ); // 被復制屬性值的類型不是對象、數組、undefined,則將被復制屬性值賦值到目標對象中 } else if ( copy !== undefined ) { target[ name ] = copy; } } } } // 返回被合並的對象,即目標對象 return target; }; // 擴展jQuery命名空間下的方法,增強行為 jQuery.extend({ method: function () { console.log('test'); }, noConflict: function () { //... }, isReady: false, // ... }); window.jQuery = window.$ = jQuery; })( window );
測試代碼如:
jQuery.method(); // test
注意:通過jQuery.extend擴展jQuery本身的方法,是jQuery的靜態方法,不能在帶有選擇器的jQuery對象上使用。
二、KISSY.mix方法(KISSY1.20版本)
1、用途
與jQuery.extend方法用途相似,不過KISSY.mix只允許一個提供對象參數,參數也不同。
2、用法
KISSY.mix(receiver , supplier [ , overwrite = true , whitelist , deep ])將 supplier 對象的成員復制到 receiver 對象上.
receiver (object) – 屬性接受者對象.
supplier (object) – 屬性來源對象.
overwrite (boolean) – 是否覆蓋接受者同名屬性.
whitelist (Array<string>) – 屬性來源對象的屬性白名單, 僅在名單中的屬性進行復制.
deep (boolean) – 是否進行深度 mix (deep copy)
3、源碼解析
(function (S, undefined) { var host = this, meta = { mix:function (r, s, ov, wl, deep) { // 參數中只有一個對象,返回對象 if (!s || !r) { return r; } // ov為undefined,重寫為true if (ov === undefined) { ov = true; } var i, p, len; // 存在白名單,將白名單中屬性(且該屬性在提供對象中)進行mix if (wl && (len = wl.length)) { for (i = 0; i < len; i++) { p = wl[i]; if (p in s) { _mix(p, r, s, ov, deep); } } // 不存在白名單,直接mix提供對象中屬性 } else { for (p in s) { _mix(p, r, s, ov, deep); } } // 返回擴展對象 return r; } }, _mix = function (p, r, s, ov, deep) { // 存在ov參數且為true(會重寫同名屬性) 或者 p屬性不被r對象枚舉(表示不重寫同名屬性) if (ov || !(p in r)) { var target = r[p], src = s[p]; // 兩個屬性值全等,函數返回為空,跳出並進行下一輪循環 if (target === src) { return; } // 來源是數組和對象,並且要求深度 mix if (deep && src && (S.isArray(src) || S.isPlainObject(src))) { // 目標值為對象或數組,直接 mix // 否則 新建一個和源值類型一樣的空數組/對象,遞歸 mix var clone = target && (S.isArray(target) || S.isPlainObject(target)) ? target : (S.isArray(src) ? [] : {}); r[p] = S.mix(clone, src, ov, undefined, true); // 擴展對象(增加對象屬性,ov為true時覆蓋對象屬性) } else if (src !== undefined) { r[p] = s[p]; } } }, seed = (host && host[S]) || {}; // console.log(seed); //Object { } host = seed.__HOST || (seed.__HOST = host || {}); // console.log(host); //window // window.KISSY獲取meta成員mix方法和擁有__HOST屬性(值為window) S = host[S] = meta.mix(seed, meta); // 擴展方法 S.mix(S, { method: function () { console.log('test'); }, method1: function () { //... }, method2: function () { //... } // ... }); //返回擴展后的KISSY對象 return S; })('KISSY', undefined)
測試代碼如:
KISSY.method(); //test