js 浅复制深复制

本文分三部分
1.先说什么是深复制浅复制 在定义上进行区分
2.深复制浅复制的各个应用场景
3.总结浅复制深复制优缺点
4.如何实现深复制
5.json实现深复制的注意事项

一.深复制浅复制的定义概念区分

什么是浅复制?
文字定义:就是原对象里有属性也是一个对象,当在复制时,这个对象属性引用值没有发生变化,还是指向原对象的对象属性。
代码表示:

const originObj={a:1,objAttr:{b:2}};
const newObj={...originObj};
newObj.objAttr===originObj.objAttr///比较结果是true, newObj.objAttr对象引用值没有变化,还是指向原对象属性

什么是深复制
文字定义:就是原对象里有属性也是一个对象,当在复制时,这个对象属性引用值发生变化被赋予新值,不指向原对象的对象属性。
代码表示:

const originObj={a:1,objAttr:{b:2}};
const newObj=JSON.parse(JSON.stringify(orginObj));
newObj.objAttr===originObj.objAttr///比较结果是false,  newObj.objAttr对象引用值变化,不指向原对象属性

二.深复制浅复制的应用场景

深度复制应用场景
深复制 主要作用是隔离两个相关变量的相互影响,有哪些场景要注意隔离影响呢
1.常规就是函数传递参数时,隔离相互影响;函数调用要传递一个对象数据时,养成深克隆后传递的习惯;不要希望别人没有修改你的原对象;另外代码会更加稳定。多人协作写代码,可能此刻是好的,下一个月就有人修改了你调用的函数,修改了你传递进来的对象。导致莫名错误。
如下面代码

function mdy(obj){
obj.subObj.xx=123;//函数内部修改了传递进来的对象 如果是你是深克隆后传递进来  就不用超心。
}

2.在react的hook里 如useEffect 依赖一个状态是对象时,只有对象引用发生变化,这个useEffect才会执行

const [stateData,setStateData]=  useState({obj:{},xx:3})
useEffect(()=>{
//do something
},[ stateData.obj ] );//这个时候 stateData每次设置就必须是深克隆

在react里应用还很多的,例如是否应该更新渲染 的判断 比较的也是引用是否发生了变化。另外全局状态的追踪记录 也是引用比较。
在对象要进行引用比较时 深克隆比较安全

浅复制应用场景
1.两种复制方式都能解决问题时,就采用浅复制,因为浅复制性能更好
什么情况下会出现浅复制解决问题就好
比如下面代码

const obj={a:1,b:{c:3}}
//你关注的值只有a时,不关注b时,就采用浅复制。即只关心基本类型的数据,不关心引用类型的数据时。采用浅复制

2.必须采用浅复制的场景
就是对象之间可以共享一个公共对象,通过共享公共对象可以节省内存,也更好的实现协同。
例如一般每个学生都有一个相同的班主任。这个时候通过浅复制学生对象再生产出一个学生对象,两个学生对象之间就能够共享班主任对象了。 代码表示如下

const stdA={age:10,name:'a' sex:boy,headTeacher:{name:"liwei",sex:'gril' }};
const stdB={...stdA};//通过浅复制出来学生b就和学生a有了相同的班主任。
stdB.age=12;
stdB.name='b'

如果有成千上万个学生共享一个校长对象,那浅复制节约内存的效果就很突出了。

三.总结浅复制深复制优缺点比较
上面已经对各个场景进行了细说。
总结记忆可以是:浅复制执行效率高,共用内存省内存;深复制隔离影响强。
所以写代码时你是想共用还是想隔离就要思考清楚。

四.深复制的实现方法

实现时要注意3个问题
1.对 基本类型 函数类型 引用类型的判断
2.要写一个深度递归,以及注意采用尾递归来优化递归性能
3.要解决循环引用问题

下面是一个具体实现

//整体想法 对基础类型 函数类型 引用类型分情况处理,用weakMap处理循环引用的情况
      const deepClone = (obj, distObj = {}, weakMap = new WeakMap()) => {
        if (!obj || typeof obj !== "object") {
          return distObj;
        }
        if (!weakMap.has(obj)) {
          weakMap.set(obj, distObj);
        }

        Object.keys(obj).forEach((key) => {
          const keyValue = obj[key];
          //函数的情况
          if (typeof keyValue === "function") {
            distObj[key] = keyValue;
            //对象情况
          } else if (keyValue && typeof keyValue === "object") {
            //说明还没有发生循环引用
            if (!weakMap.has(keyValue)) {
              //复制引用对象
              const dt = { ...keyValue };
              distObj[key] = dt;
              //把值存入weakMap
              weakMap.set(keyValue, dt);
              deepClone(dt, dt, weakMap);
            } else {
              //说明发生了循环引用
              distObj[key] = weakMap.get(keyValue);
            }
          } else {
            //基础类型情况
            distObj[key] = keyValue;
          }
        });

        return distObj;
      };

      //测试用例 构造循环引用
      const ddd = { aa: 44, c: 3, fun: () => 0 };
      const ttt = { d: 4, g: { d: ddd } };
      ddd.t = ttt;

      console.log("克隆结果", deepClone(ttt));

浅复制实现的两个方法(上面的代码能够实现浅复制)。

const obj={a:1,c:{d:2}};
const obj2={...obj};/// es6  对象扩展... 简单实现浅复制
const obj3=Object.assign({},obj);//Object.assign 这个api实现浅复制

obj.c===obj2.c===obj3.c;//三个都相对

五.常用的json实现深复制注意事项
1.underfine值不能复制
2.函数不能复制
3.循环引用问题无法解决,会报异常,需要做错误处理
具体可以看看别人的 //www.greatytc.com/p/52db1d0c1780

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容