zoukankan      html  css  js  c++  java
  • js 中引用类型 的深拷贝 和 浅拷贝的区别

    一、曾经在读JQ源码的时候,对深拷贝算是有了一点的理解。我们在项目中是不是经常会遇到这样的问题呢?

    后台返回一个数组对象(引用类型).次数在页面渲染中需要对部分数据进行处理 比如:银行卡62345092534 (这么长) 但在页面显示的时候,

    只显示中国银行(3118)但是传给后台的时候。又要传623445242整个号码,我们也许会把var oldData = res.data;

    但是我们发现两个数据都变了? 这是为什么呢? 其实就是一个深浅拷贝的问题。

    二、浅拷贝

    比如数组,对象,这样的引用类型。 

    var arr = ['js','html'];
            var oldArr = arr;
            oldArr[0] = 'css';
            console.log(arr);  // ['css','html']
            /*
                这其实是一个地址的引用。 相当于他们赋值的是指针。
            */
            //在数组的方式中可以有两种方式来避免这种问题
            //1.slice
            var b = ['vue','react'];
            var oldB = b.slice(0);
            b[0] = 'angular';
            console.log(b); //['angular','react']
            console.log(oldB); // ['vue','react']
            //2.concat();
            var c = ['d3','three','webgl'];
            var oldC = c.concat([]);
            c[0] = 'earthgL';
            console.log(c,oldC);  // "earthgL", "three", "webgl"] ["d3", "three", "webgl"]

    对象的浅复制也是一个道理。是对地址的引用而已。

     var obj = {
                name:"前端",
                age:"10"
            }
            var oldObj = obj;
            obj.name = "html + css + js";
            console.log(oldObj); //{name: "html + css + js", age: "10"}

    三、深拷贝。

    1.简单来说 深拷贝就事创建了一个新的内存空间。 他们不在会公用同一个内存空间。是两个完全独立的对象或数组。

    var defaults = {
      name: 'quber',
      age: [1, 2, 3, 4],
      child: [
       { name: 'qubernet', fun: function () { return 1; } },
       { name: 'qubernet1', fun: function () { return 2; } }
      ]
    };
    var newDefaults = $.extend(true, {},defaults );
    console.log(JSON.stringify(
    newDefaults ));

    2.JQ深拷贝源码部分

    jQuery.extend = jQuery.fn.extend = function() {
    
        var options, name, src, copy, copyIsArray, clone,
            target = arguments[0] || {},
            i = 1,
            length = arguments.length,
            deep = false;
        /*
        变量 options:指向某个源对象。
        变量 name:表示某个源对象的某个属性名。
        变量 src:表示目标对象的某个属性的原始值。
        变量 copy:表示某个源对象的某个属性的值。
        变量 copyIsArray:指示变量 copy 是否是数组。
        变量 clone:表示深度复制时原始值的修正值。
        变量 target:指向目标对象,申明时先临时用第一个参数值。
        变量 i:表示源对象的起始下标,申明时先临时用第二个参数值。
        变量 length:表示参数的个数,用于修正变量 target。
        变量 deep:指示是否执行深度复制,默认为 false。
    
        ps:源对象指的是把自己的值付给别人的对象;目标对象指的是被源对象赋值的对象
        */
    
        // 如果第一个参数传入的是布尔值
        if ( typeof target === "boolean" ) {
            deep = target;//设置deep变量,确定是深拷贝还是浅拷贝
            target = arguments[1] || {};//将目标对象设为第二个参数值。
            i = 2;//源对象的起始下标设为2(即从第三个参数开始算源对象)
        }
    
        // Handle case when target is a string or something (possible in deep copy)
        //嗯,原英文解释的很清楚
        if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
            target = {};
        }
    
        // 如果没有目标对象,那么目标对象就是jquery对象
        if ( length === i ) {
            target = this;
            --i;
        }
    
        拷贝的核心部分代码
        for ( ; i < length; i++ ) {//遍历源对象
            // Only deal with non-null/undefined values
            if ( (options = arguments[ i ]) != null ) {//options就是源对象
                // Extend the base object
                for ( name in options ) {//遍历源对象的属性名
                    src = target[ name ];//获取目标对象上,属性名对应的属性
                    copy = options[ name ];//获取源对象上,属性名对应的属性
    
                    // 如果复制值copy 与目标对象target相等,
                    //为了避免深度遍历时死循环,因此不会覆盖目标对象的同名属性。
                    if ( target === copy ) {
                        continue;
                    }
    
                    //递归地将源对象上的属性值合并到目标对象上
                    //如果是深拷贝,且待拷贝的对象存在,且是普通对象或是数组
                    //这一个判断条件非常关键,这正是之前疑问的症结
                    //首先,普通对象的定义是:通过 "{}" 或者 "new Object" 创建的
                    //回到之前的疑问,目标对象tobeCloned的属性o对象的obj不是普通对象,也不是数组,所以程序不会走到下面的分支
                    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 : {};
                        }
    
                        // 递归地拷贝
                        target[ name ] = jQuery.extend( deep, clone, copy );
    
                    } else if ( copy !== undefined ) {
                    //会走到这个分支,这个分支的处理很暴力,就是把源对象的属性,直接赋给源对象。
                    //对于上文中tobeCloned对象的属性o,没有进一步递归地拷贝,而是直接把引用赋给源对象
                    //所以改变tobeCloned的o属性时,目标对象的o属性也被改变了。
                        target[ name ] = copy;
                    }
                }
            }
        }
    
        // Return the modified object
        return target;
    };

    3.SE6提供的深拷贝的方法Object.assign(); (前提是没有属性对象)

    四、总结。

    简单来说:浅拷贝就是多个变量共用一个地址,深拷贝就是创建了多个内存空间。 (希望对你有帮助)

  • 相关阅读:
    修改Echarts 图表的坐标轴的文本的排列位置
    dataTable组件使用
    jeecg使用uploadify上传组件
    session属性的清除和非法登录
    Freemaker模板指令
    Freemarker的循环通过assign指令引入计数变量
    测试计划模板
    python+requests接口自动化测试框架实例详解教程(米兔888)
    jmeter(二十二)内存溢出原因及解决方法
    Jmeter(四)_逻辑控制器详解
  • 原文地址:https://www.cnblogs.com/createGod/p/7347296.html
Copyright © 2011-2022 走看看