当前位置: 首页 > 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怎么处理图片
  • @angular/forms 源码解析之双向绑定
  • Angular 响应式表单之下拉框
  • CSS中外联样式表代表的含义
  • ES6系统学习----从Apollo Client看解构赋值
  • iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • linux学习笔记
  • SegmentFault 技术周刊 Vol.27 - Git 学习宝典:程序员走江湖必备
  • Spring思维导图,让Spring不再难懂(mvc篇)
  • Vim Clutch | 面向脚踏板编程……
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 对象管理器(defineProperty)学习笔记
  • 湖南卫视:中国白领因网络偷菜成当代最寂寞的人?
  • 机器学习 vs. 深度学习
  • 力扣(LeetCode)965
  • 让你成为前端,后端或全栈开发程序员的进阶指南,一门学到老的技术
  • 使用putty远程连接linux
  • 与 ConTeXt MkIV 官方文档的接驳
  • 3月27日云栖精选夜读 | 从 “城市大脑”实践,瞭望未来城市源起 ...
  • ​ArcGIS Pro 如何批量删除字段
  • # Swust 12th acm 邀请赛# [ E ] 01 String [题解]
  • #设计模式#4.6 Flyweight(享元) 对象结构型模式
  • (ZT)一个美国文科博士的YardLife
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (附源码)springboot 房产中介系统 毕业设计 312341
  • (附源码)计算机毕业设计SSM智慧停车系统
  • (切换多语言)vantUI+vue-i18n进行国际化配置及新增没有的语言包
  • (三分钟)速览传统边缘检测算子
  • (十六)串口UART
  • (算法二)滑动窗口
  • (已解决)什么是vue导航守卫
  • (转)fock函数详解
  • (转)PlayerPrefs在Windows下存到哪里去了?
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .NET Core 2.1路线图
  • .net 前台table如何加一列下拉框_如何用Word编辑参考文献
  • .netcore 获取appsettings
  • .vue文件怎么使用_vue调试工具vue-devtools的安装
  • /etc/sudoers (root权限管理)
  • /etc/X11/xorg.conf 文件被误改后进不了图形化界面