JavaScript浅层克隆与深度克隆示例详解
1相关知识点
- 浅克隆就是将栈内存中的引用复制一份,赋给一个新的变量,本质上两个指向堆内存中的同一地址,内容也相同,其中一个变化另一个内容也会变化。
 
- 深克隆就是创建一个新的空对象,开辟一块内存,然后将原对象中的数据全部复制过去,完全切断两个对象间的联系。
- 区别:浅克隆和深克隆最大的区别就是对引用值的处理了,即浅克隆之后你改我也改,深克隆之后你改我不改。(PS:原始值的处理一样)
- 原始值(栈数据stack):Number,Boolean(false/true),String,undefined,null
- 引用值(堆数据heap):Array,Object,function···Date,RegExp
 
2浅层克隆
在浅层克隆中,原始值的克隆没问题,只是值的拷贝,不会出现你改我改的问题。但是引用值的克隆,就会出现你改我也改的问题,因为浅层克隆的是地址,即指向的是同一空间。
2.1浅克隆函数
functionclone(origin,target){
vartarget=target||{};
//容错,即防止用户不传递目标参数。若用户传递了参数就用,若没传则拿一个空对象当目标
for(varpropinorigin){
target[prop]=origin[prop];
}
returntarget;
}
2.2运用实例
functionclone(origin,target){
vartarget=target||{};
for(varpropinorigin){
target[prop]=origin[prop];
}
returntarget;
}
varobj={
name:'abc',
age:'18',
sex:'male',
card:['a','b','c'],
book:{
name:'ccc',
sbook:{
name:'aaa'
}
}
};
varnewobj={};
clone(obj,newobj);
运行代码如下:
3深度克隆
进行深度克隆之后,对于引用值的克隆的问题就会和原始值一样我改你不改,因为在深度克隆中虽然是相同的东西,但是指向不同的空间。即深度克隆之后,值各自独立,互不影响。
3.1深克隆步骤分析
需要进行深度克隆的对象如下:
varobj={
name:'abc',//原始值
age:'18',//原始值
sex:'male',//原始值
card:['a','b','c'],//引用值
book:{//引用值
name:'ccc',//原始值
sbook:{//引用值
name:'aaa'//原始值
}
}
};
varobj1={};
(1)首先需要遍历要克隆的对象
方法:for(varpropinorigin){···}
for(varpropinorigin){
	···
}
(2)依次判断是不是原始值
方法:typeof(),即若为原始值,就直接拷贝;若为引用值(typeof(···)返回的值是object),则进行递归操作。需要注意是的typeof(null)=='object',所以得排除这一个情况。
if(origin[prop]!=="null"&&typeof(origin[prop])=='object'){
	···
	//递归
}else{
target[prop]=origin[prop];
}
(3)判断是数组还是对象
方法:toString(推荐),constructor,instanceof(后两个会涉及到父子域的小问题,虽然遇到的可能不是很大)
vartoStr=Object.prototype.toString,
arrStr="[objectArray]";
if(toStr.call(origin[prop])==arrStr){
	···//数组
}else{
	···//对象
}
(4)建立相应的数组或对象
方法:建立一个新的同名空数组/对象,并将原始对象中的数组或对象当成一个新的原始对象,再次将其中的数据拷贝到目标对象的同名空数组/对象里面。即递归开始拷贝数组或对象里面的数据,并递归执行第(1)步。递归完成之后,再依次进行下一个数据的克隆。
vartoStr=Object.prototype.toString,
arrStr="[objectArray]";
if(toStr.call(origin[prop])==arrStr){
	target[prop]=[];
}else{
	target[prop]={};
}
newobj={
name:'abc',
age:'18',
sex:'male',
card:[]
//建立一个新的同名空数组,并把obj的card数据当成一个原始对象,再次拷贝到obj1的card里面
//即递归开始拷贝数组或对象里面的数据,递归执行第(1)步
//执行完数组card拷贝之后,开始同理拷贝下一个对象book···
}
3.2深克隆函数
functiondeepClone(origin,target){
vartarget=target||{},
toStr=Object.prototype.toString,
arrStr="[objectArray]";
for(varpropinorigin){
if(origin.hasOwnProperty(prop)){
if(origin[prop]!=="null"&&typeof(origin[prop])=='object'){
if(toStr.call(origin[prop])==arrStr){
target[prop]=[];
}else{
target[prop]={};
}
deepClone(origin[prop],target[prop]);
}else{
target[prop]=origin[prop];
}
}
}
returntarget;
}
使用三目运算符简化后的代码如下:
//使用三目运算符简化后
functiondeepClone(origin,target){
vartarget=(target||{}),
toStr=Object.prototype.toString,
arrStr="[objectArray]";
for(varpropinorigin){
if(origin.hasOwnProperty(prop)){
if(origin[prop]!=="null"&&typeof(origin[prop])=='object'){
target[prop]=toStr.call(origin[prop])==arrStr?[]:{};
deepClone(origin[prop],target[prop]);
}else{
target[prop]=origin[prop];
}
}
}
returntarget;
}
3.3运用实例
//使用三目运算符简化后
functiondeepClone(origin,target){
vartarget=(target||{}),
toStr=Object.prototype.toString,
arrStr="[objectArray]";
for(varpropinorigin){
if(origin.hasOwnProperty(prop)){
if(origin[prop]!=="null"&&typeof(origin[prop])=='object'){
target[prop]=toStr.call(origin[prop])==arrStr?[]:{};
deepClone(origin[prop],target[prop]);
}else{
target[prop]=origin[prop];
}
}
}
returntarget;
}
运行代码如下:
3.4hasOwnProperty
hasOwnProperty()方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(即是否有指定的键)。
语法:obj.hasOwnProperty(prop)
参数:要检测的属性的字符串形式表示的名称,或者Symbol。
返回值:用来判断某个对象是否含有指定的属性的布尔值。
描述:所有继承了Object的对象都会继承到hasOwnProperty方法。这个方法可以用来检测一个对象是否含有特定的自身属性;和in运算符不同,该方法会忽略掉那些从原型链上继承到的属性。
用法:
a.使用hasOwnProperty方法判断属性是否存在
b.区别自身属性与继承属性
c.遍历一个对象的所有自身属性
d.使用hasOwnProperty作为属性名
具体知识点请参考Object.prototype.hasOwnProperty()
若对象里面编写了原型属性,但遍历的时候并不想让其显示出来,就可以使用对象名.hasOwnProperty(属性名)来判断是否是自身属性,若是自己的则返回值为true,若不是自身原型属性则返回值为false。实例如下:
varobj={
	name:'ABC',
	age:'18',
	sex:'male',
	__proto__:{
		heart:'happy'
	}
}
for(varpropinobj){
	//配套使用,起到一个过滤的作用,不把原型链上的数据弄出来
	if(obj.hasOwnProperty(prop)){
		console.log(obj[prop]);//ABC18male
	}
}
个人笔记,欢迎大家交流探讨!
总结
到此这篇关于JavaScript浅层克隆与深度克隆的文章就介绍到这了,更多相关JavaScript浅层克隆与深度克隆内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。
