javascript实现引用数据类型的深拷贝和浅拷贝详解

关于引用类型值的详解,请看另一篇随笔 https://www.cnblogs.com/jinbang/p/10346584.html

 

深拷贝和浅拷贝,也就是引用数据类型栈和堆的知识点。深浅拷贝的原型都是Object,深拷贝指向的堆内存不一样,浅拷贝指向的堆内存一样):
如何区分深拷贝与浅拷贝,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B没有发生变化,说明是深拷贝。如果B也跟着发生了变化,说明是浅拷贝。
let obj = { name: "jin", arr: ["red","blue","black"]};
let obj1 = {};
Object.defineProperties(obj1, Object.getOwnPropertyDescriptors(obj)); // 深拷贝
Object.assign(obj1, obj); // 深拷贝
obj1 = JSON.parse(JSON.stringify(obj)); // 深拷贝
obj1 = { ...obj }; // 深拷贝
obj1 = deepCopy(obj); // 使用到深拷贝函数 obj1 = obj; // 浅拷贝 obj1 = Object.assign(obj); // 浅拷贝

 

下面是deepCopy()深拷贝函数,其中使用到了判断变量的类型函数

      // 判断变量的类型
      function getType(obj){
        let str = Object.prototype.toString.call(obj); // 检测基本类型值,引用类型值的类型
        let map = {
          '[object Boolean]': 'boolean',
          '[object Number]': 'number',
          '[object String]': 'string',
          '[object Function]': 'function',
          '[object Array]': 'array',
          '[object Date]': 'date',
          '[object RegExp]': 'regExp',
          '[object Undefined]': 'unfefined',
          '[object Null]': 'null',
          '[object Object]': 'object'
        };
        if(obj instanceof Element){
          return 'element';
        }
        return map[str];
      }

      // 深拷贝函数
      function deepCopy(p){
        let obj;
        let str = getType(p);
        if(str === 'array'){
          obj = [];
          for(let i=0;i<p.length;i++){
            // obj.push(p[i]); // 不能这样写,因为会把array的堆内存也会复制过去
            obj.push(arguments.callee(p[i])); //回调自己
          }
        }else if(str === 'object'){
          obj = {};
          for(let i in p){
            // obj[i] = p[i]; // 不能这样写,因为会把object的堆内存也会复制过去
            obj[i] = arguments.callee(p[i]); //回调自己
          }
        } else {
          return p;
        }
        return obj;
      }

 

需要特别注意的是,使用JSON.parse(JSON.stringify(x))不是一个很好的选择,也算是它们的坑吧:

对象是由构造函数生成的:会丢弃对象的constructor,因为JSON.stringify()只能序列化对象的可枚举的自有属性
时间对象:变成字符串
RegExp,Error对象:变成空对象
函数,undefined:会被丢失
NaN,Infinity和-Infinity:变成null
function Person(name){
      this.name = name;
    }
    var person = new Person('liai');
    
    var test = {
      name: 'jin',
      person: person, //对象是由构造函数生成的:会丢弃对象的constructor
      date: new Date(), //序列化后返回是字符串,不是时间对象
      regexp: new RegExp('\\w+'), //序列化后返回空对象:{}
      err: new Error(),  //序列化后返回空对象:{}
      fun: function(){}, //序列化后会丢失
      undef: undefined, //序列化后会丢失
      nun: NaN, //序列化后返回null
    };
    console.log(test);
    console.log(JSON.parse(JSON.stringify(test)));

 

 

posted @ 2019-02-01 18:30  chenjinbang  阅读(597)  评论(0编辑  收藏  举报