详解JavaScript对象的深浅复制
作者:Claiyre 发布时间:2024-05-11 09:36:30
前言
从层次上来看,对象的复制可以简单地分为浅复制和深复制,顾名思义,浅复制是指只复制一层对象的属性,不会复制对象中的对象的属性,对象的深复制会复制对象中层层嵌套的对象的属性。
在复制对象时,除了要复制对象的属性外,还要兼顾到是否保留了对象的constructor属性,是否对每一种数据类型(JavaScript常见的数据类型有String,Number,Boolean,Data,RegExp,Array,Funtion,Object)都实现正确的复制。项目中,我们可以根据实际情况,决定需要实现什么样程度的复制。
本文是我在复制对象方面的一些心得总结,由浅复制到深复制,由只复制简单属性到复制Function,RegExp等复杂属性,层层递进。如有陈述不当之处,烦请指出,不胜感激。
正文
浅复制
浅复制只会依次复制对象的每一个属性,不会对这些属性进行递归复制。下面是一个简单的浅复制实现。
//对象浅复制
function shadowCopy(obj){
if(typeof obj !== 'object') return obj;
for(var prop in obj){
if(obj.hasOwnProperty(prop)){
newObj[prop] = obj[prop];
}
}
return newObj;
}
仔细观察,不难发现上述方法的缺陷:
1.不能正确实现数组的浅复制
2.复制操作丢失了对象的constructor属性
好,我们现在已经发现了问题所在,只需针对性地解决,一个还算完美的浅复制对象的方法就诞生了!
//对象浅复制
function shadowCopy(obj){
if(typeof obj !== 'object') return ;
var newObj;
//保留对象的constructor属性
if(obj.constructor === Array){
newObj = [];
} else {
newObj = {};
newObj.constructor = obj.constructor;
}
for(var prop in obj){
if(obj.hasOwnProperty(prop)){
newObj[prop] = obj[prop];
}
}
return newObj;
}
浏览器中测试一下:
var arr1 = [0,1,2];
console.log(arr1);
console.log(shadowCopy(arr1));
var arr2 = [0,1,2,[3,4,5]],
arr2Copy = shadowCopy(arr2);
console.log(arr2);
console.log(arr2Copy);
arr2Copy[3][0] = 6;
console.log(arr2[3][0]); //6
Good! 可以正确实现数组复制和并且保留constructor了,但细心的你一定发现了,浅复制后的对象的 arr2Copy[3] 和 arr2[3] 指向的是一个对象,改变其中一个,同时也会改变另一个。我们想要实现的是 复制,但这并不是复制呀!
这是浅复制的一个弊端所在,接下让我们看看深复制是怎样解决这个问题的。
深复制
深复制需要层层递归,复制对象的所有属性,包括对象属性的属性的属性....(晕~)
如果只是需要简单地复制对象的属性,而不用考虑它的constructor,也不用考虑函数,正则,Data等特殊数据类型,那这里有一个深复制的小trick,两行代码即可:
function deepCopy(obj){
if(typeof obj !== "object"){ return ;}
var str = JSON.stringify(obj);
return JSON.parse(str);
}
大多数情况下,上面的就可以满足要求了,但一些时候,我们需要把函数,正则等特殊数据类型也考虑在内,或者当前环境不支持JSON时,上面的方法也就不适用了。这时,我们可以通过递归来实现对象的深层复制,如下:
function deepCopy(obj){
if(typeof obj !== "object"){ return ;}
var newObj;
//保留对象的constructor属性
if(obj.constructor === Array){
newObj = [];
} else {
newObj = {};
newObj.constructor = obj.constructor;
}
for(var prop in obj){
if(typeof obj[prop] === 'object'){
if(obj[prop].constructor === RegExp ||obj[prop].constructor === Date){
newObj[prop] = obj[prop];
} else {
//递归
newObj[prop] = deepCopy(obj[prop]);
}
} else {
newObj[prop] = obj[prop];
}
}
return newObj;
}
先用上面的例子测试:
棒!可以正确实现多维数组的复制,再看是否能实现函数和正则的复制:
function Person(name){
this.name = name;
this.age = age;
this.search = new RegExp(name);
this.say = function(){
console.log(this.name + "今年" + this.age + "岁了");
}
}
var p1 = new Person("Claiyre",20),
p2 = deepCopy(p1);
console.log(p1);
console.log(p2);
p2.age = 22;
p1.say();
p2.say();
圆满完成!!
稍加整理,我们就可以得到一个较为通用的js对象复制函数:
function deepCopy(obj){
var newObj = obj.constructor === Array ? []:{};
newObj.constructor = obj.constructor;
if(typeof obj !== "object"){
return ;
} else if(window.JSON){
//若需要考虑特殊的数据类型,如正则,函数等,需把这个else if去掉即可
newObj = JSON.parse(JSON.stringify(obj));
} else {
for(var prop in obj){
if(obj[prop].constructor === RegExp ||obj[prop].constructor === Date){
newObj[prop] = obj[prop];
} else if(typeof obj[prop] === 'object'){
//递归
newObj[prop] = deepCopy(obj[prop]);
} else {
newObj[prop] = obj[prop];
}
}
}
return newObj;
}
结语
面向对象的编程语言,其核心是对象,因此深入了解对象的相关操作,纵向比较异同,对学习过程是极有好处的。
以上所述是小编给大家介绍的JavaScript对象的深浅复制网站的支持!
来源:http://www.cnblogs.com/nuannuan7362/p/6642143.html


猜你喜欢
- 如果你现在正在使用Restful API,并且你需要通过web项目来构建json格式字符串的响应,那么这篇文章将帮助你使用javascrip
- 什么是事件呢?按下键盘某个按键,鼠标移动,包括点击关闭按钮都可以算是事件操作。Pygame事件pygame.event.EventType&
- Axios是一款网络前端请求框架,基本用法如下:1. Axios基本用法:const response = await Axios.crea
- 获取操作系统的当前运行状态和负载情况,是一个系统管理员的基本技能,因为这对我们日常排查故障,定位问题有着非常紧密的联系,比如查看当前系统的基
- 在我的前一篇教程《九宫格基本布局》中,我介绍了用相对定位加绝对定位的方法来制作九宫格的基本布局。这是一种比较符合人们惯性思维的方法,好像制作
- 本人在CentOS6.4上安装万mysql后,无法通过root进入,因为安装的时候,并没有设置root密码,似乎有个初始随机密码,但是不记得
- Python 通过pywin32模块调用WindowsAPI接口,实现对特定进程加载模块的枚举输出并检测该PE程序模块所启用的保护方式,此处
- 进程和线程是计算机软件领域里很重要的概念,进程和线程有区别,也有着密切的联系,先来辨析一下这两个概念:1.定义进程是具有一定独立功能的程序关
- 本文实例讲述了Python字符串、列表、元组、字典、集合。分享给大家供大家参考,具体如下:附加:python的很多编译器提供了代码补全功能,
- matplotlib是python最著名的绘图库,它提供了一整套和matlab相似的命令API,十分适合交互式地进行制图。而且也
- MS SQL基本语法及实例操作 一:建表并初始化 ============================ create database
- 1.IP代理某些网站会检测一段时间内某IP的访问次数,若访问次数过多会禁止访问,这时需要设置一些代理服务器,每隔一段时间换一个代理。IP代理
- 最近工作需要用到序列匹配,检测相似性,不过有点复杂的是输入长度是不固定的,举例为:input_and_output = [1, 2,
- CSRF(Cross Site Request Forgery, 跨站域请求伪造)是一种网络的×××方式。我的理解是,比如你访问过招商银行的
- 在vue项目中, mock数据可以使用 node 的 express模块搭建服务1. 在根目录下创建 test 目录, 用来存放模拟的 js
- 性能不理想的系统中除了一部分是因为应用程序的负载确实超过了服务器的实际处理能力外,更多的是因为系统存在大量的SQL语句需要优化。为了获得稳定
- python中数据处理是比较方便的,经常用的就是读写文件,提取数据等,本博客主要介绍其中的一些用法。Pandas是一个强大的分析结构化数据的
- 本文实例讲述了golang实现http服务器处理静态文件的方法。分享给大家供大家参考,具体如下:新版本更精简:package mainimp
- 偶然将想到的一个如何判断鼠标从哪个方向进入一个容器的问题。首先想到的是给容器的四个边添加几块,然后看鼠标进入的时候哪个块先监听到鼠标事件。不
- 在了解了XHTML 2的进展之后,我们再来看看X/HTML 5 的进展。X/HTML 5酷在什么地方章节元素的构想X/HTML 5引入新的元