jQuery.extend()方法源码解析

1.变量的含义:

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; /* 存放一个标志,表示源对象当前属性值是否是数组 */

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

2.1. 第一个参数是boolean时候执行。

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

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

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

3.1. if语句:满足target不是对象也不是函数时执行。

3.2. 满足条件的target值有可能是以字面量方式创建的boolean,number,string。

3.3. 不会出现target值为undefined和null,前面初始化时候已经过滤。
if ( typeof target !== "object" 
    && !jQuery.isFunction(target) ) {
    target = {};
}

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

4.1. arguments长度等于i的值得时候,表示target = arguments[arguments.length-1],
这时候的源对象是arguments[arguments.length] = undefined,显然这是没意义的。

4.2. jQuery在出现这种情况时,将target对象设置为自身,然后修改i指向target原先的指向。

4.3. 我们可以通过这个方法对jQuery进行扩展。
if ( length === i ) {
target = this;
--i;
}

5.for代码块,实现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 ];
            
            /* 为了避免在递归深拷贝过程中,出现了无限循环:(看后面代码片1,2)
               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;
};

6.代码片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

运行结果

7.代码片2

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

8.代码片3

/* 过滤掉属性值为undefiend的属性,没过滤属性值为null的属性,可以测试以下代码:可以修改copy!= undefined来实现过滤null*/
var target = {}
var original = {
   name: null
}
console.log($.extend(target,original));
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,560评论 18 399
  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,204评论 0 4
  • 1.JQuery 基础 改变web开发人员创造搞交互性界面的方式。设计者无需花费时间纠缠JS复杂的高级特性。 1....
    LaBaby_阅读 1,321评论 0 2
  • Elasticsearch 需要依赖 Java 8+ 环境。 跟着 官方文档 安装 Elasticsearch。直...
    与蟒唯舞阅读 300评论 0 1
  • Author: Zongwei Zhou | 周纵苇Weibo: @MrGiovanniEmail: zongwe...
    MrGiovanni阅读 4,954评论 0 12