jQuery.extend()源码解析

jQuery.extend()源码解析

var target
    ,options /* 指向源对象 */
    ,name,   /*  键名 */
    ,i = 1   /* 指向的源对象在arguments中的索引 */
    ,length = arguments.length /* 参数的个数 */
    ,deep = false   /* 标志是否深拷贝,没有boolean值的时候默认为flase,浅复制 */
    ,src     /* 存储target对象的当前属性 */
    ,copy    /* 存储源对象当前属性的值 */
    ,target = arguments[0] || {} /* 过滤掉undefined 和 null */
    ,clone;  /* 深复制时候存放target[name]值 */
    ,copyIsArray; /* 存放一个标志,表示源对象当前属性值是否是数组 */

代码功能:extend函数提供用户指定是否深拷贝的功能通过在第一个参数传递boolean值,检测函数第一个值是否是boolean值

/* 1.第一个参数是boolean时候执行,
   2.第一个参数是boolean类型即是target的指向错了,i指向也错了,必须进行修改,并且重置deep标志
*/

if ( typeof target === "boolean" ) {
    deep = target;
    target = arguments[1] || {}; /* 过滤第2个参数值为undefined,null */
    i = 2;
}

代码功能:因为js中对那些不是对象不是函数的值设置属性方法是无效的,这里过滤这些值,保证target指向一个可以设置属性的对象

/* 1.if语句:满足target不是对象也不是函数时执行。
   2.满足条件的target值有可能是以字面量方式创建的boolean,number,string。
   3.不会出现target值为undefinednull,前面初始化时候已经过滤。
*/

if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
    target = {};
}

代码功能:extend()函数实现了当传入的参数有效对象个数不足够赋值给target和源对象时,默认将target指向自身

/* 1.arguments长度等于i的值得时候,表示target = arguments[arguments.length-1],
    这时候的源对象是arguments[arguments.length] = undefined,显然这是没意义的,
   2.jQuery在出现这种情况时,将target对象设置为自身,然后修改i指向target原先的指向 
   3.我们可以通过这个方法对jQuery进行扩展
*/

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

代码功能:实现target对象扩展

/* 从第一个源对象开始遍历arguments,*/
for ( ; i < length; i++ ) {

    /* 以上我们已经将arguments中的项过滤到target指向,以下if在源对象值为undefiend和null时进行过滤*/

    if ( (options = arguments[ i ]) != null ) {
        for ( name in options ) {
            src = target[ name ];
            copy = options[ name ];

            /* 为了避免在递归深拷贝过程中,出现了无限循环:(看后面代码片12)
               1.向extend()方法传入的源对象拥有属性值为目标对象,并且目标对象中有属性引用了目标对象本身,
               2.源对象的属性引用了源对象自身*/

            if ( target === copy ) {
                continue;
            }

            /* 判断是否满足深拷贝的条件:
            1.deep标志为true,
            2.源对象当前属性(name)的值存在,
            3.源对象当前属性值是数组,{}或者是由Object创建的对象*/

            if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {

                /* copyIsArray 是标示源对象当前属性值是否是数组,通过这个标志分别对源对象当前属性
                值为对象和源对象当前属性值为数组的情况分开处理*/

                if ( copyIsArray ) {

                    /* 如果不设置为false,下一次既使满足深拷贝的条件进入后,如果源对象当前属性值为对象,会按照数组进行处理*/
                    copyIsArray = false;

                    /* clone存放了target[name]的值,值的如果不存在或者类型不是数组时,将其赋值空数组,否则值不改变 */
                    clone = src && jQuery.isArray(src) ? src : [];

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

                    /* 递归调用extend进行深拷贝*/
                    target[ name ] = jQuery.extend( deep, clone, copy );

                    /* 过滤源对象属性值为undefined的属性,没有过滤属性值为null的属性,看以下代码片3*/
                } else if ( copy !== undefined ) {
                    target[ name ] = copy;
                }
            }
        }
    }

    /* 返回修改后的对象*/
    return target;
};

代码片1

/* 1.target对象属性值引用自身,并且original对象的属性引用target,注释if(target == copy)中的continue后无限循环最后
报错*/
/* 2.错误信息:Uncaught RangeError: Maximum call stack size exceeded(超过最大调用堆栈内存)*/
var target = {};
target.proper = target;
var original = {};
original.proper = target;
$.extend(true,target,original);

注释continue
运行结果

代码片2

 /*bug:
 2.original对象存在属性引用其自身,报错信息和上面一致 */
var target = {};
target.proper = '属性';
var original = {};
original.proper = original;
console.log($.extend(true,target,original));

代码片3

/* 过滤掉属性值为undefiend的属性,没过滤属性值为null的属性,可以测试以下代码:可以修改copy!= undefined来实现过滤null*/
var target = {}
var original = {
   name: null
}
console.log($.extend(target,original));
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值