• 由jQuery深拷贝引发的学习


    先前对javascript的继承学的很模糊,由此我就百度各种文章,然文章千奇百怪,虽不乏精妙之言,却独无对吾之口味,由此从jquery
    中的extend方法开始学起,首先上源码copy自jQuery1.7版本

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

    // Handle a deep copy situation
    if ( typeof target === "boolean" ) {
    deep = target;
    target = arguments[1] || {};
    // skip the boolean and the target
    i = 2;
    }

    // Handle case when target is a string or something (possible in deep copy)
    if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
    target = {};
    }

    // extend jQuery itself if only one argument is passed
    if ( length === i ) {
    target = this;
    --i;
    }

    for ( ; i < length; i++ ) {
    // Only deal with non-null/undefined values
    if ( (options = arguments[ i ]) != null ) {
    // Extend the base object
    for ( name in options ) {
    src = target[ name ];
    copy = options[ name ];

    // Prevent never-ending loop
    if ( target === copy ) {
    continue;
    }

    // Recurse if we're merging plain objects or arrays
    if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
    if ( copyIsArray ) {
    copyIsArray = false;
    clone = src && jQuery.isArray(src) ? src : [];

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

    // Never move original objects, clone them
    target[ name ] = jQuery.extend( deep, clone, copy );

    // Don't bring in undefined values
    } else if ( copy !== undefined ) {
    target[ name ] = copy;
    }
    }
    }
    }

    // Return the modified object
    return target;
    };


    笼统看一遍,很难产生什么直观的感觉,先看该方法的定义
    合并两个或更多的对象汇集成到第一个对象中

    jQuery.extend([deep,]Target[,object1,][objectN]);
    

     
     可以去看一下该函数的说明,有以下几种用法

    jQuery.extend(object);
    
    jQuery.extend(object1,object2,objectN);
    
    jQuery.extend(bool,object1);
    
    jQuery.extend(bool,object1,object2,objectN);
    

     
    我们从上面的方法来分析jQuery是怎么处理的,首先是jQuery.extend(object)。一个参数的时候,目标对象将会被jquery本身代替

    //对象1
    var obj1={name:"hello",sex:"man",fruits:["1","2"],bb:{name:"gg"}};

    $.extend(obj1);
    document.write($.name);

    //result:
    //hello

    对象的属性已经被附加到jQuery中了,看看其实现

    //关键之处,参数的长度如果和预设的长度相等的话,那么目标对象将会被改变为自身
    if ( length === i ) {
    target = this;
    --i;
    }

    然后就是对象的拷贝

    //这里的拷贝只是简单的拷贝,通常说的浅拷贝,与深拷贝的不同继续看下面
    else if ( copy !== undefined ) {
    target[ name ] = copy;
    }

    那么深拷贝与浅拷贝有什么不同呢?看例子

    浅拷贝

    //对象1
    var obj1={name:"hello",sex:"man",fruits:["1","2"],bb:{name:"gg"}};

    $.extend(obj1);
    obj1.name="hello is changed!";
    obj1.fruits[0]="1 is changed";
    obj1.bb.name="gg is changed";
    document.write($.name+"<br>"+$.fruits[0]+"<br>"+$.bb.name);

    //results:
    //hello
    //1 is changed
    //gg is changed
    //结果表明obj1的array与object类型的数据被改变后会影响到目标对象,而值类型
    //确不会,现在是不是有点意思了,深拷贝就是要排除这个影响,让他们互不侵犯

    深拷贝

    //对象1
    var obj1={name:"hello",sex:"man",fruits:["1","2"],bb:{name:"gg"}};

    $.extend(true,obj1); //调用时候变成了2个参数,第一个布尔值就是深拷贝标识
    obj1.name="I changed!";
    obj1.fruits[0]="1 is changed";
    obj1.bb.name="gg is changed";
    document.write($.name+"<br>"+$.fruits[0]+"<br>"+$.bb.name);

    //results:
    //hello
    //1
    //gg
    //现在源对象的改变再也不会影响到目标对象了,下面看看jquery是怎么实现的

    关键点把对象或数组的拷贝转化为值的拷贝

     if ( copyIsArray ) {
    copyIsArray = false;
    clone = src && jQuery.isArray(src) ? src : [];
    //对象是否是数组,是的话记录对象本身,否则创建一个新的空数组
    } else {
    clone = src && jQuery.isPlainObject(src) ? src : {};
    //对象是否为object,是的话记录对象本身,否则创建一个新的空对象
    }

    //关键之处,对array或object进行迭代,把他们的值进行拷贝
    target[ name ] = jQuery.extend( deep, clone, copy );

    现在再看jQuery.extend(object1,object2,objectN);、jQuery.extend(bool,object1,object2,objectN);这两种用法就很容易理解是怎么实现的了。

    //对象1
    var obj1={name:"hello",sex:"man",fruits:["1","2"],bb:{name:"gg"}};
    //对象2
    var obj2={name:"world",sex:"woman",fruits:["3","4"],bb:{name:"mm"}};
    //对象3
    var obj3={name:"!",sex:"undefind",fruits:["5","6"],bb:{name:"gm"}};

    $.extend(obj1,obj2,obj3);
    obj3.bb.name="gm is changed"; //如果是obj2.bb.name="aa";是不会影响obj1的,因为参数是依次遍历的哦,前面的会被后面的覆盖
    for(var i in obj1){
    if(jQuery.type(obj1[i])=="array"||jQuery.type(obj1[i])=="object")
    {
    for(var i2 in obj1[i]){document.write("<br>"+obj1[i][i2]);}
    }else{
    document.write("<br>"+obj1[i]);

    }
    }
    //results:
    //!
    //undefind
    //5
    //6
    //gm is changed 这里是浅拷贝的缘故哦

    $.extend(true,obj1,obj2,obj3);   深拷贝
    //results:
    //!
    //undefined
    //5
    //6
    //gm

    以上就是jquery用来实现“继承”的方法,和传统的OO继承比较,不同的是,“子类”的属性、方法会被“父类”的属性、方法给覆盖,这让我有点费解,也许

    是被先入为主的思想所左右了,也奇怪jquery的开发人员怎么不搞的传统点,也许他们觉得这样也就够了,也许我没理解透彻。

    扯着扯着,又得写下,传统的OO继承在JS中的实现

    看个例子

    //将Object.prototype上的toString方法重写,以便测试
    Object.prototype.toString=function(){document.write("I am object");};

    //父类
    function ParentFunction(){
    this.toString=function (){document.write("I am parent");}
    }
    ParentFunction.prototype.toString=function(){document.write("I am parent prototype");};

    //子类
    function SubFunction(){
    this.toString=function(){document.write("I am sub");}
    }


    //SubFunction继承了ParentFunction,通过将原型new一个ParentFunction对象来建立关系
    SubFunction.prototype=new ParentFunction();
    //由于上面的prototype被重写了,而我们又必须让原型链完整,构造函数属性指向SubFunction
    SubFunction.prototype.constructor=SubFunction;

    //可以再在prototype上添加方法
    //
    SubFunction.prototype.toString=function(){document.write("I am sub prototype");};

    var test=new SubFunction();
    test.toString(); //result: I am sub

    结果貌似不怎么明显表达意思,那么把SubFunction里的方法去掉

    //result: I am parent

    有点意思了,方法调用的是父类的本地代码里的方法,再将ParentFunction里的方法去掉

    //result: I am parent prototype

    调用的是父类prototype上的方法,继续把ParentFunction.prototype.toString去掉如何?

    //result: I am object 

    调用了Object对象上的方法,别奇怪,那是因为Object是所有对象的父类。

    上个图,也许能理解的清楚点


    学习做此小记,最后欢快一下。

    “辛苦十几年,你也不过是红警里500块一个的工程师,一条狗咬死一片的那种。。。”

  • 相关阅读:
    理解C语言中指针常量和常量指针区别!不要再搞混了~
    哪座城市可以安放程序员的灵魂,一线城市与二三线城市该如何择别?
    Linux 之父如何定义 "Linux" !主要想让黑客、计算机学生使用,学习和享受!
    程序员的凡尔赛文学!作为低调人群的程序员,“凡”起来又是怎样的一番景象呢?
    40个Java集合面试问题和答案
    从关系型数据库到非关系型数据库
    redis安装报错
    redis简介
    不满足依赖关系
    EL表达式中引用隐式变量
  • 原文地址:https://www.cnblogs.com/whosedream/p/2391467.html
Copyright © 2020-2023  润新知