当前位置: 首页 > news >正文

复习Javascript专题(四):js中的深浅拷贝

基本数据类型的复制很简单,就是赋值操作,所以深浅拷贝也是针对Object,Array这类引用类型数据。

浅拷贝对于字符串来说,是值的复制,而对于对象来说则是对对象地址的复制;

而深拷贝的话,它不仅将对象的各个属性逐个复制出来,还将各个属性所包含的对象也依次复制出来,相当于在堆区又新开了一块地存放,主要采取递归来实现。

实现方式

原生JS实现:

浅拷贝:

let originObj={ color:['red','green'], num:5 };

function shallowClone(obj){
    let newObj=(obj instanceof Array) ? []:{};
    for(let item in obj){
        if(obj.hasOwnProperty(item)){ // 避免列举出原型上的属性
            newObj[item]=obj[item];
        }
    }
    return newObj;
}
let cloneObj=shallowClone(originObj);

深拷贝:

   function deepClone(obj){
       let newObj=(obj instanceof Array)? [] : {};
       for(let item in obj){
           if(obj.hasOwnProperty){
               const val=obj[item];
               debugger
               newObj[item]=typeof val==='object' ? deepClone(val) : val;
           }
       }
       return newObj;
   }
   let cloneObj2=deepClone(originObj);

其实,这种深拷贝的实现还是有些问题的,比如日期正则对象无法复制,还有一个是循环引用,类似闭包会内存泄露一样,这样的对象深拷贝也会陷入一个闭环,直到栈溢出。
为了解决这个问题,就得先判断这个对象是否等于原对象。

function deepClone(obj){
    let tempArr=[];
    let newObj=(obj instanceof Array) ? [] : {};
    tempArr.push(obj);
    for(let item in obj){
        if(typeof obj[item] === 'object'){
            const index=tempArr.indexOf(obj[item]); 
            // 如果已存在,证明引用了相同对象,那么无论是循环引用还是重复引用,我们返回引用就可以了
            if(index>-1){
                newObj[item]=tempArr[index];
            }else{
                newObj[item]=obj[item];
            }
        }else{
            newObj[item]=obj[item];
        }        
    }
    return newObj;
}

ES6实现

    let newObj1=Object.assgin({},originObj);
    let newObj2={...obj}; // 数组用[...obj]
注:Object.assgin和扩展运算符实现的都是浅拷贝。

JSON实现:

这种方法简单是简单,不过这个方法有以下缺陷:

1.会忽略函数对象以及原型对象,正则会复制成空对象,而日期对象会变成字符串。

2.它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object; 
   
3.如果对象中存在循环引用的情况无法正确处理。

按需取用吧。

  let originObj={fn:function(){console.log(111)}, colors:['red','gree'],reg:/\s/g};
  let newObj=JSON.parse(JSON.stringify(originObj));

第三方库实现:

转自链接:深入剖析 JavaScript 的深复制

Underscore —— _.clone()

顺便安利下underscore,真的挺好用的一个库: Underscore中文文档

这个方法实际上是一种浅复制 (shallow-copy),所有嵌套的对象和数组都是直接复制引用而并没有进行深复制。

        let originObj={ color:['red','green'], num:5 };
        let newObj=_.clone(originObj);
        newObj.colors.push('grey');
        originObj.colors; // ['red','green','grey']; 

源码逻辑很简单:(当然调用的其他方法也是underscore的)

    // Create a (shallow-cloned) duplicate of an object.
    _.clone = function(obj) {
        if (!_.isObject(obj)) return obj;
        return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
    }

jQuery —— $.extend()

这个用法很简单:

    let originObj={ color:['red','green'], num:5 };
    let shallowClone=$.extend({},originObj); // 浅拷贝
    let deepClone=$.extend(true,{},originObj); // 深拷贝,第一个参数表示是否深度合并对象

lodash —— _.clone() / _.cloneDeep()

lodash深拷贝——这个算是这几个里面最完善的方法了, 日期函数正则对象通通都能复制。

在lodash中关于复制的方法有两个,分别是_.clone()_.cloneDeep()。其中_.clone(obj, true)等价于_.cloneDeep(obj)

没引入的可以点击上面的文档链接去直接改动代码试试看。

另外,查资料过程中还看到这么一个词: 结构化克隆算法
还有这一篇资料也有参考,也写得比较详细了: JS的深浅拷贝

相关文章:

  • stackoverflow:为什么排序后的数组要比未排序数组运行快3倍以上?
  • 胡小林:把日常生活中碰到的事变成我们发露忏悔的机会
  • 分布式消息队列 Kafka
  • 网站如何做好SEO优化,该怎么选择SEO软件?
  • JAVA入门到精通-第67讲-sqlserver作业讲评
  • Tcp/Ip 三次握手与四次挥手
  • jQuery操作表格(table)的常用方法、技巧汇总
  • [转]GitLab Continuous Integration (GitLab CI/CD)
  • 实战开发正则归纳
  • Android Activity生命周期图解
  • JavaScript权威指南手记(一)
  • 阿里巴巴下一代云分析型数据库AnalyticDB入选Forrester Wave™ 云数仓评估报告 解读...
  • 美团容器平台架构及容器技术实践
  • 利用aiohttp制作异步爬虫
  • 怎么在线编辑图片 PS怎么处理图片
  • 【跃迁之路】【519天】程序员高效学习方法论探索系列(实验阶段276-2018.07.09)...
  • 【跃迁之路】【669天】程序员高效学习方法论探索系列(实验阶段426-2018.12.13)...
  • 2018一半小结一波
  • Apache Spark Streaming 使用实例
  • C++类的相互关联
  • js ES6 求数组的交集,并集,还有差集
  • js数组之filter
  • Redis的resp协议
  • Vue官网教程学习过程中值得记录的一些事情
  • 从零开始在ubuntu上搭建node开发环境
  • 番外篇1:在Windows环境下安装JDK
  • 关于Java中分层中遇到的一些问题
  • 关于List、List?、ListObject的区别
  • 汉诺塔算法
  • 如何利用MongoDB打造TOP榜小程序
  • 十年未变!安全,谁之责?(下)
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 你对linux中grep命令知道多少?
  • ​​​​​​​ubuntu16.04 fastreid训练过程
  • ​iOS安全加固方法及实现
  • ​LeetCode解法汇总2182. 构造限制重复的字符串
  • ​草莓熊python turtle绘图代码(玫瑰花版)附源代码
  • ​你们这样子,耽误我的工作进度怎么办?
  • #1014 : Trie树
  • #每天一道面试题# 什么是MySQL的回表查询
  • #图像处理
  • $forceUpdate()函数
  • (+4)2.2UML建模图
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (Matalb时序预测)WOA-BP鲸鱼算法优化BP神经网络的多维时序回归预测
  • (WSI分类)WSI分类文献小综述 2024
  • (二)正点原子I.MX6ULL u-boot移植
  • (附源码)ssm户外用品商城 毕业设计 112346
  • (三分钟)速览传统边缘检测算子
  • (一)Dubbo快速入门、介绍、使用
  • (转)scrum常见工具列表
  • (转)视频码率,帧率和分辨率的联系与区别
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • .net Stream篇(六)