jQuery源码学习之五 (jQUery继承方法)

jQuery 利用extend进行扩展。


参考jQuery API关于extend 的用法:

$.extend([deep],target,object1,objectN)

$.fn.extend(object)


extend函数结构分析:

jQuery.extend = jQuery.fn.extend = function() {
    变量的声明
    if(){}       //是否是深拷贝
    if(){}      //参数是否正确
    if(){}      //是否是插件的情况
    for() {     //多个对象情况
        if()    //防止循环引用
        if()    //深拷贝
        else if //浅拷贝
    }
}

extend函数逐行分析:

if 第一个参数是boolean值,deep将保持传递进来的boolean值,target 变为第二个参数,i变为2

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


if 赋值完后的target不是对象也不是函数,则 target赋值为一个空{};
jQuery.extend = jQuery.fn.extend = function() {

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

       if () {}
       if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
            target = {};
       }
       ...
    }
}
if  实参的长度等于i ( 意义等同于 当第一个参数不是boolean时,i=1,即实参的长度为1,只传入一个参数;否则i=2 ,即实参的长度为2,传入2个参数)也就是说,没有传入目标对象时,target赋值为this;i的长度-1;
jQuery.extend = jQuery.fn.extend = function() {

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

       ...
       if ( length === i ) {
         target = this;
         --i;
       }
       ...
}

开始for循环

如果除boolean值外,传入了target参数(实参个数大于等于3),则从target参数之后的参数开始循环;

如果除boolean值外,没有传入了target参数(实参个数小于等于2),则从boolean值之后开始循环(没有boolean参数,则从第一个参数开始循环)。

for  in 内的第一个if防止了循环引用,循环引用实例:

var a={n:1};
var b={0:a};
a[n]=b[0];        //发生循环引用,会无限制循环

接下来的if ...else...区分 深拷贝和浅拷贝

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

        ...
     for ( ; i < length; i++ ) {
        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;
                                clone = src && jQuery.isArray(src) ? src : []; 
                            } else {
                           //src 是对象则赋值给clone,否则 clone赋值为空{}
                           clone = src && jQuery.isPlainObject(src) ? src : {};
                             } 
                           target[ name ] = jQuery.extend( deep, clone, copy ); //递归实现深拷贝
                        } else if ( copy !== undefined ) {
                            target[ name ] = copy; 
                       }
            }
        }
    }
    return target;
}