jquery 源码分析三(extend函数解析)

这次主要分析的是JQuery中的extend函数,extend函数在JQuery中占的作用十分明显,在后期JQuery方法的添加上,基本是使用这个函数来添加到JQuery对象和prototype上的。这个函数另一个重要作用是在框架开发的时候使用,可以直接对JQuery增加新的功能。

说明了重要性之后,就开始讲解函数了(函数的使用方法就不讲了,具体可以看官方文档:http://api.jquery.com/jQuery.extend/#jQuery-extend-target-object1-objectN)。首先是函数的位置:

jQuery.extend = jQuery.fn.extend = function() {
        //some code
}

可以看到,extend函数直接加在了jQuery对象和prototype上(jQuery.fn =jQuery.prototype),这是因为函数内部存在判断,如果要拓展的target缺失的话,就会直接用this。这样就可以方便开发者们自己确定函数放的位置了。

接下来就是具体函数内容分析了,下面这一段是先定义一系列需要的变量,其中target是要扩展的对象,deep是指是否深度复制,i=1是因为target已经默认指向了arguments[0]了,再接下来读取参数的时候,arguments[i]就可以直接从第二项开始了。:

var src, copyIsArray, copy, name, options, clone,
        target = arguments[0] || {},
        i = 1,
        length = arguments.length,
        deep = false;

    // 当第一参数是布尔值时,就让target等于第二个参数,而第一个参数确定为是否深度复制
    if ( typeof target === "boolean" ) {
        deep = target;

        // target 往后移动一位,i自加
        target = arguments[ i ] || {};
        i++;
    }

    // 处理当target为字符串或其他的时候
    if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
        target = {};
    }

    // 当只有一个参数或者只有是否深度复制和被复制的变量时,将target指向this(一般为jQuery)
    if ( i === length ) {
        target = this;
        i--;
    }

通过以上这些代码的处理,就可以解决了deep和target的赋值问题,接下来就是通过循环来将值复制到target中。

//支持添加多个被添加变量
for ( ; i < length; i++ ) {
        // 只处理值不为undefined和null的情况
        if ( (options = arguments[ i ]) != null ) {
            for ( name in options ) {
                src = target[ name ];
                copy = options[ name ];

                // 当copy指向target时,有可能导致无限循环,遇到这种情况直接跳过
                if ( target === copy ) {
                    continue;
                }

                // 当确定是深度复制后,用递归进行
                if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
                                //判断copy的类型,若target下该项没有的时候,建立相同类型的变量
                    if ( copyIsArray ) {
                        copyIsArray = false;
                        clone = src && jQuery.isArray(src) ? src : [];

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

                    // 进行深度复制,同时不改变copy
                    target[ name ] = jQuery.extend( deep, clone, copy );

                // 浅复制,直接等于即可
                } else if ( copy !== undefined ) {
                    target[ name ] = copy;
                }
            }
        }
    }

    // 返回完成的target
    return target;