一、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
