zoukankan      html  css  js  c++  java
  • 对象的深浅拷贝

    一.定义:

    1.浅拷贝

    创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

    2.深拷贝

    将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象

    浅拷贝存在问题

    let a = {

      a:'a'

    }

    let b = a;

    b.a = 'b';

    console.log(a.a);//b

    深拷贝方法

    一.乞丐版:JSON.stringify()

    缺点:(从数据类型分析  时间对象、正则对象 Error对象 、function Undefined 、NaN 正负无穷 、循环引用 和 丢失constructor)

    1.如果拷贝对象是个时间对象,JSON.stringify()方法会将时间对象转换为时间字符串,JSON.parse()反转后也只是将时间转为字符串形式而不是对象。

    2.new RegExp()和new Error()对象 会被 JSON.stringify()转化为空对象字符串:'{}'

    3.函数和undefined 会被JSON.stringify()转化为undefined JSON.parse()反转时报错

    4.NaN、Infinity和-Infinity会被转换为null

    5.JSON.stringify()只能序列化对象的可枚举的自有属性 如果拷贝的对象是 构造函数new 生成的  会丢失对象的constructor属性

    6.如果对象中存在循环引用的情况也无法正确实现深拷贝;

    二.基础版(没有考虑数组等情况)

    function clone(obj){
      if(typeof obj !== 'object') return obj;
      let newObj = {};
      for(let k in obj){
        newObj[k] = clone(obj[k]);
      }
      return newObj;
    }

    三.考虑数组情况

    function clone(obj){
      if(typeof obj !== 'object') return obj;
      let newObj = Array.isArray(obj) : [] : {};
      for(let k in obj){
        newObj[k] = clone(obj[k]);
      }
      return newObj;
    }

    四.考虑循环引用情况

    function clone(obj,map=new Map()){
      if(typeof obj !== 'object') return obj;
      let newObj = Array.isArray(obj)?[]:{};
      if(map.get(obj)){
        return map.get(obj);
      }
      map.set(obj,newObj);
      for(let k in obj){
        newObj[k] = clone(obj[k],map);
      }
      return newObj;
    }

    五.完整版

    //数据类型
    const mapTag = '[object Map]';
    const setTag = '[object Set]';
    const arrayTag = '[object Array]';
    const objectTag = '[object Object]';

    const boolTag = '[object Boolean]';
    const dateTag = '[object Date]';
    const errorTag = '[object Error]';
    const numberTag = '[object Number]';
    const regexpTag = '[object RegExp]';
    const stringTag = '[object String]';
    const symbolTag = '[object Symbol]';

    //判断数据是否为对象
    function isObject(data){
    const type = typeof data;
    return data!==null && (type === 'object' || type === 'function');
    }

    //初始化一个相应数据类型的新对象
    function getInit(data){
    const Fn = data.constructor;
    return new Fn();
    }

    //判断数据类型
    function getType(data){
    return Object.prototype.toString.call(data);
    }

    //抽象foreach方法
    function foreach(arr,fn){
    let index = 0;
    while(index<arr.length){
    fn(arr[index],index);
    index++;
    }
    return arr;
    }

    //clone方法
    function clone(target,map=new WeakMap()){
    if(!isObject(target)) return target;

    let type = getType(target);
    let newTarget = getInit(type);

    if(map.get(target)){
    return map.get(target);
    }
    map.set(target,newTarget);

    //克隆set
    if(type == setTag){
    target.foreach(v=>{
    newTarget.add(clone(v).map);
    })
    return newTarget;
    }

    //克隆map
    if(type == mapTag){
    target.foreach((v,k)=>{
    newTarget.set(k,clone(v,map));
    })
    return newTarget;
    }

    //克隆数组或对象
    if(type == mapTag){
    target.foreach((v,k)=>{
    newTarget.set(k,clone(v,map));
    })
    return newTarget;
    }




    if(isArray){
    foreach(target,function(val,key){
    newTarget[key] = val;
    })
    }else{
    foreach(keys,function(val,key){
    newTarget[val] = clone(target[val],map);
    })
    }
    return newTarget;
    }

  • 相关阅读:
    [转]检查浏览器是否支持javascript和cookie
    Ruby语法学习
    [转]Office Word 2007鼠标操作无效
    JS选择图片,显示缩略图
    IE开发工具条IEDevToolBar下载
    [转]120个 Web 开发工具 (下)
    JQuery收藏
    [转]120个 Web 开发工具 (上)
    [转]GridView自动序号
    [转]GridView 常用事件删除,更新,删除,取消等
  • 原文地址:https://www.cnblogs.com/jayking1314/p/14831701.html
Copyright © 2011-2022 走看看