jq中extend函数中的deep参数

         昨天在研究继续研究JS插件的时候注意到了extend这个函数,然后就用几个示例去加深对它的印象,不过在过程中对于deep这个参数产生了疑惑。当jq1.1.4版本后extend这个函数增加了一个参数deep,用来进行选择是否深拷贝,深浅拷贝这里我就不说了,这里直接用例子来看一下


给出3个例子,大家应该就明白了:


1.我们可以发现当我们去改变a中的age值的时候,b中改变

var a = {tom: { age: 15 }};
var b = { tom: { age: 14 } }
extend(a, b);
a.tom.age = 25;
console.log(a.tom.age); //25
console.log(b.tom.age);//25

2.我们可以发现当我们去改变a中的age值的时候,b中没有改变

var a = {tom: { age: 15 }};
var b = { tom: { age: 14 } }
extend(true,a, b);
a.tom.age = 25;
console.log(a.tom.age); //25
console.log(b.tom.age);//14



3.我们可以发现当我们去改变a中的age值的时候,b中没有改变

var a = {tom: { age: 15 }};
var b = { tom: { age: 14 } }
extend(false,a, b);
a.tom.age = 25;
console.log(a.tom.age); //25
console.log(b.tom.age);//14


我们可以发现3个例子的区别就是第一个参数deep是否存在和为true和false,而且第一个例子是浅拷贝,第二个和第三个都是深拷贝

这里可以有2个结论:

1.这个函数默认就是浅拷贝

2.传true和false都是深拷贝


一开始对于第2个结论很不理解,讲道理true为深拷贝,那么false肯定为浅拷贝呀,为什么都一样呢?在网上查了很多资料,发现还是不明白,后来去官网查了一下知道(证明以后我们查东西还是去官网比较靠谱,网上很多博客都是断章取义),第一个参数不能为false。https://api.jquery.com/jquery.extend/  (可以去看中文的文档,也可以用chrome浏览器翻译)


Warning: Passingfalse for the first argument is not supported.


原来不能传false,之所以这样是我们一直都是惯性思维,理解true为深,那么false肯定为浅咯~   -。-(惯性思维害死人,我还一直纠结为什么会这样)


其实到这里我们都是知其然,不知其所以然,在纠结这个问题的过程中,我查了源码,终于知道其所以然了。

target =  arguments [ 0 ] | | { }  

 //就是这一句话~(大家可以定位到这句话),它是把这个函数的第一个参数传递给target,最重要的是这里用了一个 | | 或,如果当我第一个是假的话就直接赋值一个空对象给target,这样就可以理解,为什么我们可以传true不能传false了,当我们传true的时候为真,它就直接把true给它了,当我传false的时候为假,它就会把一个空对象给target。


因为上面这个条件,我们就可以解释为什么当进行后面那个判断时,我传false会进不去的原因了,就是因为typeof (target)为object!!!!!

if ( typeof (target) === "boolean" ) {//如果第一个参数是boolean类型,则将该参数赋给deep,即是否深拷贝
        deep = target;
         target = arguments[1] || {};

      // skip the boolean and the target 
         i = 2;
     }


然后再看一个例子:

var empty={};
var a = {tom: { age: 15 }};
var b = { tom: { age: 14 } }
extend(empty,a,b);
empty.tom.age = 25;
console.log(empty.tom.age);//25
console.log(a.tom.age); //15
console.log(b.tom.age);//25


我们可以发现,当我们去浅拷贝的时候,它只是会影响到最后一个对象的参数,这个也可以理解,因为后面的参数会覆盖前面的,所以浅拷贝的时候,最后被合并的对象(empty)引用的是最后一个参数对象( b )的属性。



所以当我们对插件参数进行覆盖的时候最好用这种方式:

第一个参数为true,第二个参数为空对象,就是为了不让其他对象的值被覆盖掉。



var empty={};
var a = {tom: { age: 15 }};
var b = { tom: { age: 14 } }
empty=extend(true,{},a,b);
empty.tom.age = 25;
console.log(empty.tom.age);//25
console.log(a.tom.age); //15
console.log(b.tom.age);//14



最后附上别人对这个函数的源码解析:

jQuery.extend = jQuery.fn.extend = function() {
    /*
        传入的对象分为扩展对象和被扩展对象
    */
    var options, name, src, copy, copyIsArray, clone, //
        target = arguments[0] || {},    //被扩展的对象
        i = 1,                          //设置扩展对象的起始值,默认从第二项开始
        length = arguments.length,      //传递参数的个数,以便下面循环扩展对象使用
        deep = false;                   //默认浅复制

    /*
        处理深层拷贝或浅拷贝情况
        extend(Boolean,src1,src2..srcN);
    */
    if ( typeof target === "boolean" ) {

        deep = target;  //将deep设为target,此时target为传进来的Boolean值,true or false;

        target = arguments[ i ] || {};  //重新设置被扩展对象,为参数的第二项

        i++;    //重设扩展对象的起始值,从第三项开始
    }

    /*
        被扩展的不是对象或函数,可能是String,Number或其他;
        extend("",src1,src2...srcN);
    */

    if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
        target = {}; //重新设置target的值为空对象
    }

    /*
        当只传入一个对象
        extend(src1);
        将target设为jQuery对象或者jQuery.prototype,来扩展jQuery静态属性方法或是实例属性方法
        $.extend(src1);   //扩展jQuery对象
        $.fn.extend(src1) //扩展jQuery.prototype
    */
    if ( i === length ) {
        target = this;
        i--;    //重设扩展对象起始值,从第0个开始
    }

    /*
        被扩展对象和扩展对象所有情况处理完毕,开始循环进行拷贝
        对从i开始的多个参数进行遍历
    */

    for ( ; i < length; i++ ) {
        
        if ( (options = arguments[ i ]) != null ) {  //只处理有定义扩展对象
            //扩展基本对象
            for ( name in options ) {       //循环每一项扩展对象
                src = target[ name ];       
                copy = options[ name ];     

                // 防止循环引用,window === window.window.window
                if ( target === copy ) {
                    continue;
                }

                /*
                    对象或数组做深拷贝
                    deep:判断是否要深拷贝
                    copy:保证copy存在
                    jQuery.isPlainObject:判断copy是否是一个纯粹的对象,通过{} 或 new Object 创建
                    jQuery.isArray:判断是否为数组
                */
                if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
                    //为数组
                    if ( copyIsArray ) {
                        copyIsArray = false; //设为false,以便下次再重新判断是否为数组
                        clone = src && jQuery.isArray(src) ? src : [];  //设置clone为一个数组

                    } else {
                        clone = src && jQuery.isPlainObject(src) ? src : {}; //设置clone为一个对象
                    }

                    //递归深度拷贝
                    target[ name ] = jQuery.extend( deep, clone, copy );

                //过滤未定义的值
                } else if ( copy !== undefined ) {
                    target[ name ] = copy;
                }
            }
        }
    }

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








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值