详解JavaScript对象深拷贝
详解JavaScript对象深拷贝
在几乎所有编程语言中,对象都以引用形式保存给变量、复制给其他变量。JavaScript语言也是如此。因此简单的进行赋值操作进行复制仅仅是对对象数据的引用地址进行一个传递,并不会将对象内部的所有属性进行一个完整的复制。也就是说,当修改其中一个对象,另一个变量也会发生改变,因为他们本质上指向了同一个对象引用。
let obj={a:1
};
let copyObj=obj;
obj.a=2;
//输出2
console.log(copyObj.a);
这种语言特性有时候对开发人员来说是有益的。但有时候,特定的开发场景会要求“完全复制”对象,也就是复制后的对象和复制前的对象完全独立,互不影响。这个过程就被称为“深拷贝”。相对应的,前面那种简单的赋值复制操作就称为“浅拷贝”。
深拷贝是许多JavaScript面试官会问的问题,经常作为手写代码的题目出现在面试场景中。下面本文就将详细解析JavaScript中深拷贝的实现方式。
JSON复制
这种深拷贝方式的原理是使用JSON.parse、JSON.stringify函数,对目标对象进行一次转义之后重新生成来实现复制:
//json拷贝,不能正确复制undefined、NaN、函数等数据类型
function jsonCopy(obj1){//{"a":[1,2],"b":{"a":"a","b":{"a":1}},"c":true,"d":null}let obj2=JSON.stringify(obj1);obj2=JSON.parse(obj2);return obj2;
}let a={a:[1,2],b:{a:'a',b:{a:1}},c:true,d:null,e:undefined,f:function(a){return a+1;},g:NaN
};let g=jsonCopy(a);
console.log(g);
程序输出如下:
对于常规场景,JSON复制是最简洁的深拷贝写法。但是从上面的示例中可以看到,JSON复制并不能解析a对象的f和g属性。这说明JSON复制不能处理一些特定的数据类型,例如undefined、NaN、function等其他数据类型(具体情况视浏览器而定)。但可以保证的是,JSON复制可以正确处理以下数据类型的对象属性:数组、普通对象、数字、字符串、布尔值。
递归复制
这种深拷贝方式使用一个递归函数去循环读取目标对象的每一个属性,将每一个属性重新赋值给新对象,最终将新对象返回:
//深拷贝
function deepCopy(obj1,obj2={}){for(let i in obj1){if(obj1.hasOwnProperty(i)){if(Array.isArray(obj1[i])){obj2[i]=[];deepCopy(obj1[i],obj2[i]);}else if(typeof obj1[i]==="function"){obj2[i]=obj1[i];}else if(obj1[i] instanceof Object){obj2[i]={};deepCopy(obj1[i],obj2[i]);}else{obj2[i]=obj1[i];}}}return obj2;
}let a={a:[1,2],b:{a:'a',b:{a:1}},c:true,d:null,e:undefined,f:function(a){return a+1;},g:NaN
};let f=deepCopy(a);
console.log(f);
程序输出如下:
从程序输出结果可以看到,递归复制可以正确解析所有数据类型的对象属性。虽然递归调用会在运行时保留一个函数栈,从而产生一定的内存和计算性能损耗。但是正常情况下,开发人员需要复制的目标对象不会是一个深度很深的对象(通常情况下,大约深度达到100层以后,递归复制会卡顿)。因此递归复制是一种非常好的深拷贝实现方式。
但是有一点需要注意,如果目标对象有一个属性是Function数据类型,那么JavaScript语言本身也没有提供给开发人员太好的方法来“完全复制”一个函数出来,因此无法复制函数。函数的复制仍然是一个引用的传递(当修改其中一个函数的可变属性时,另一个对象的函数属性也会修改)。
详解JavaScript对象深拷贝相关推荐
- 【干货分享|建议收藏】2w字爆肝详解 JavaScript对象
感激相遇 你好 我是阿ken 作者:请叫我阿ken 链接:请叫我阿ken主页链接 来源:CSDN 著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.
- 详解jQuery对象与DOM对象的相互转换
一直以来对于通过jQuery方式获取的对象,却不能直接使用JavaScript的方法很不理解,现在知道,原来jQuery获得的对象并不和我们平时使用getElementById获得的对象一样.所以一些 ...
- window 程序报错 自动重启_好程序员web前端教程之详解JavaScript严格模式
好程序员web前端教程之详解JavaScript严格模式,严格模式(Strict mode)是由ECMA-262规范定义的新兴JavaScript标准,发布于2009年12月第五版.旨在改善错误检查功 ...
- 详解 javascript中offsetleft属性的用法(转)
详解 javascript中offsetleft属性的用法 转载 2015-11-11 投稿:mrr 我要评论 本章节通过代码实例介绍一下offsetleft属性的用法,需要的朋友可以做一 ...
- 详解JavaScript变量类型判断及domReady原理 写得很好
原文:详解JavaScript变量类型判断及domReady原理 我们知道,在开发JavaScript时候,经常要判断JavaScript变量类型,此 JavaScript教程 详细介绍JS变量的判断 ...
- es6字符串添加html标签,JavaScript_详解JavaScript ES6中的模板字符串,在 ES6 中引入了一种新的字符 - phpStudy...
详解JavaScript ES6中的模板字符串 在 ES6 中引入了一种新的字符串字面量 - 模板字符串,除了使用反引号 (`) 表示,它们看上去和普通的字符串没有什么区别.在最简单的情况下,他们就是 ...
- js模板字符串自定义类名_详解JavaScript ES6中的模板字符串
这篇文章主要介绍了详解JavaScript ES6中的模板字符串,JS的ES6版本带来诸多简洁化方面的重大改进,需要的朋友可以参考下 在 ES6 中引入了一种新的字符串字面量 - 模板字符串,除了使用 ...
- 详解Javascript本地存储的方式、区别及应用场景
详解Javascript本地存储的方式.区别及应用场景 一.方式 javaScript本地缓存的方法我们主要讲述以下四种: cookie sessionStorage localStorage ind ...
- 详解 JavaScript 的 IIFE 语法
详解 JavaScript 的 IIFE 语法 IIFE 语法 IIFE 语法的一些变体 小括号去哪儿了? 命名的 IIFE 防止连接文件时出现问题 使用箭头函数代替函数表达式 一些不推荐的立即调用函 ...
最新文章
- TD商用将迈重要一步 六大运营商年底建网试验
- Ajax技术原理小结
- 你网络成瘾了吗 小心一堆怪病找上你
- 大项目微服务架构设计
- 被窃听、被定位:“裸奔时代”还有隐私吗?
- python爬虫--爬取豆瓣top250电影名
- 虚拟机和主机之间建立虚拟磁盘
- SVM(三),支持向量机,线性不可分和核函数
- php+mysql 图书管理系统源码AfireHong
- 【HTTPServer】借助Python建立简易的HTTP服务
- Book Sharing
- Vue 中常见的面试题/知识点整理
- 京东图片列表、左侧导航栏、网易新闻列表、京东页面布局、京东轮播图
- html5左侧边导航右边显示页面,bootstrap如何实现左侧导航栏右侧网页
- iOS菜鸟学习——UITextField return键隐藏键盘
- javascript数据类型边边角角
- php tp5微信支付,tp5微信支付踩坑
- web.xml提示the processing instruction target matching [xX][mM][lL] is not allowed
- 学园狂想曲 出云战记2 Izumo2通关感言
- Flexe2.0 学习笔记三(得用STATE实现一个组件登录窗体)
热门文章
- Apollo配置中心与本地配置优先级
- C语言:字符串API拷贝_strcpy(),strncpy,给(数组名)赋值字符串要用strcpy
- 汉诺塔递归python搬运次数_Python3.x | 汉诺塔递归理解
- c/c++程序员的黄金发展方向:音视频开发
- Linux重新读写分区的命令,用partprobe、blockdev、hdparm、partx命令在Linux中重新加载分区表...
- 2023-03-24:音视频mp3和h264混合(muxer)编码为mp4,用go语言编写。
- phpmailer 私密抄送_phpmailer发送邮件(附件)
- 【Ctfer训练计划】——(四)
- 音视频笔记-----经验公式(experience formula)
- C语言编程求仙,求21位凌波仙子数(C语言实现)