zoukankan      html  css  js  c++  java
  • 解析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、源码解析
    // 源码解析 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 );
    View Code
        测试代码如:
    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
    
  • 相关阅读:
    052-141
    052-140
    052-139
    052-138
    需要做笔记的页面
    日期总是显示1900/01/01 0:00:00
    延迟加载的树控件
    (简单)关于summary的注释
    江南检测
    fineui动态添加用户控件
  • 原文地址:https://www.cnblogs.com/yangjunhua/p/2704222.html
Copyright © 2011-2022 走看看