解析jQuery.extend和淘宝KISSY.mix方法源码
一、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、源码解析
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 源码解析 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