zoukankan      html  css  js  c++  java
  • javascript篇-浅拷贝与深拷贝

    理解javascript 的浅拷贝与深拷贝,首先看一下js的数据类型:

    js有5种基本数据类型:undefined,null,boolean,number,string

    还有一种复杂的数据类型(也叫引用类型),即 对象

    1.对于基本数据类型:

    他们的值在内存中占据着固定大小的空间,并被保存在栈内存中。当一个变量向另一个变量复制基本类型的值,会创建这个值的副本,并且我们不能给基本数据类型的值添加属性

    上面代码中:a是基本数据类型(number),b是a的一个副本,它们两者都占有不同的内存空间,其中一个值的改变不会影响另一个值。

    2.对于引用类型:

    复杂的数据类型即是引用类型,它的值是对象,保存在堆内存中,包含引用类型值的变量实际上包含的不是对象本身,而是一个指向该对象的指针。从一个变量向另一个变量复制引用类型的值,复制的其实是指针地址而已,因此两个变量最终都指向同一个对象

    上述代码中,将a的值赋值给b以后,b的值得改变也导致了a的值的改变,这其实就是浅拷贝

    但是很多情况下这都不是我们要的效果,我们希望b的改变不会影响到a,这就是下面要将的深拷贝了,

    (1) 数组的深拷贝

    对于数组我们可以使用slice()和concat()方法来实现深拷贝,

    (2) 对象的深拷贝

    1:手动复制:

    这种比较麻烦,而切属性多层嵌套的情况下,也必须要手动嵌套复制,否则,还是会改变

    像这种对象只有一层的情况下可以使用Object.assign()函数(函数参考:https://blog.csdn.net/qs8lk88/article/details/79018481) 

    3. 转成Json再转回来

    这样做是真正的Deep Copy,这种方法简单易用。

    但是这种方法也有不少坏处,譬如它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。

    这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,即那些能够被 json 直接表示的数据结构。RegExp对象是无法通过这种方式深拷贝。

    也就是说,只有可以转成JSON格式的对象才可以这样用,像function没办法转成JSON。

    4. 递归拷贝

    function deepClone(initalObj, finalObj) {    
      var obj = finalObj || {};    
      for (var i in initalObj) {        
        if (typeof initalObj[i] === 'object') {
          obj[i] = (initalObj[i].constructor === Array) ? [] : {};            
          arguments.callee(initalObj[i], obj[i]);
        } else {
          obj[i] = initalObj[i];
        }
      }    
      return obj;
    }
    var str = {};
    var obj = { a: {a: "hello", b: 21} };
    deepClone(obj, str);
    console.log(str.a);
    

      

    上述代码确实可以实现深拷贝。但是当遇到两个互相引用的对象,会出现死循环的情况。

    为了避免相互引用的对象导致死循环的情况,则应该在遍历的时候判断是否相互引用对象,如果是则退出循环。

    改进版代码如下:

    function deepClone(initalObj, finalObj) {    
      var obj = finalObj || {};    
      for (var i in initalObj) {        
        var prop = initalObj[i];        // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
        if(prop === obj) {            
          continue;
        }        
        if (typeof prop === 'object') {
          obj[i] = (prop.constructor === Array) ? [] : {};            
          arguments.callee(prop, obj[i]);
        } else {
          obj[i] = prop;
        }
      }    
      return obj;
    }
    var str = {};
    var obj = { a: {a: "hello", b: 21} };
    deepClone(obj, str);
    console.log(str.a);
    

      

    5、使用Object.create()方法

    function deepClone(initalObj, finalObj) {    
      var obj = finalObj || {};    
      for (var i in initalObj) {        
        var prop = initalObj[i];        // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
        if(prop === obj) {            
          continue;
        }        
        if (typeof prop === 'object') {
          obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
        } else {
          obj[i] = prop;
        }
      }    
      return obj;
    }
    

    直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。

    6. jquery 有提供一个$.extend可以用来做 Deep Copy。

    7. 另外一个很热门的函数库lodash,也有提供_.cloneDeep用来做 Deep Copy。

    var _ = require('lodash');
    var obj1 = {
        a: 1,
        b: { f: { g: 1 } },
        c: [1, 2, 3]
    };
    var obj2 = _.cloneDeep(obj1);
    console.log(obj1.b.f === obj2.b.f);
    // false
    

      

      

  • 相关阅读:
    .NET 内存分配笔记
    MYSQL知识点
    NOPI导入导出
    【链接】各类学习资源
    【原创】重绘winform的GroupBox
    高仿淘宝滑动验证码插件
    Winform窗体控件级权限处理
    .NET中的Func委托用法
    关于IBatisNet的配置文件中数据库连接字符串加密处理
    Oracle连接字符串大全
  • 原文地址:https://www.cnblogs.com/keleyz/p/9505721.html
Copyright © 2011-2022 走看看