什么是拷贝?
克隆 是在JavaScript中必学的一个知识点,也是比较常见的问题。克隆(拷贝)就是将一个对象(obj1)里面的属性和方法等复制到另一个对象(obj2),且克隆之后,对一个对象进行改动,不会影响到另一对象,就是两者互不影响,还是两个不同的个体。
它分为浅度拷贝和深度拷贝两种,下面将对这两种进行解释和讨论。
1. 浅度拷贝
<script type="text/javascript">
var obj1 = {
name : 'IT协会',
age : 'the Tenth',
sex : ['male','female']
}
function shallowClone(prpo){
var temp = {}; //var 一个临时空对象
for (var i in prpo){ //利用for...in函数进行遍历对象
temp[i] = prpo[i];
}
return temp; //返回temp对象
}
var obj2 = shallowClone(obj1);
</script>
复制代码
上述的代码就是将obj1对象中的name,age,sex复制一份到obj2,我们可以在浏览器的控制台看一下,如下:
从上述可以看到obj2中也有了与obj1一样的属性和sex数组,那现在我们就想如果我改变一下obj1中的属性或数组会有什么变化呢?接下来我们来操作一下:
<script type="text/javascript">
var obj1 = {
name : 'IT协会',
age : 'the Tenth',
sex : ['male','female']
}
function shallowClone(prpo){
var temp = {}; //var 一个临时空对象
for (var i in prpo){ //利用for...in函数进行遍历对象
temp[i] = prpo[i];
}
return temp;//返回temp对象
}
var obj2 = shallowClone(obj1);
obj1.name = '信息技术协会';
obj1.age = 10;
obj1.sex.push('middle');
</script>
复制代码
上面我只改变了obj1中的属性和数组,那我们想一下obj2是否会发生变化呢?接下来我们来看一下输出是怎样的:
我们可以看出来,obj1中的的age和name、sex均变化了,但是为什么在obj2中为什么sex会跟着变化呢,而age和name不会?
说到这里我们就要来理解一下基本数据类型和引用值类型
我们知道JavaScript中的基本数据数据类型有Undefined、Null、Boolean、Number和String5种,引用类型有Object、Array、Date、RegExp、Function、包装类等,我们学过数据结构与算法的同学应该知道栈内存和堆内存的区别。
- 基本数据类型是存放在栈内存中的,引用类型是堆内存中的对象
原因:
name和age的值属于基本类型,所以拷贝的时候传递的就是该数据段;但是sex的值是堆内存中的对象,所以sex在拷贝的时候传递的是指向sex对象的地址,无论复制多少个sex,其值始终是指向父对象的sex对象的内存空间,如下图:
简洁代码(另外一种方法):
使用Object构造函数的方法Object.assign()
通过复制一个或多个对象来创建一个新的对象。Object.assign()用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。(注意:
可枚举属性
)
语法:Object.assign(target, …sources),第一个参数是我们要输出的目标对象,后面是一个或多个源对象
<script type="text/javascript">
var obj1 = {
name : 'IT协会',
age : 'the Tenth',
sex : ['male','female']
}
var another = {
name:"qietuzai",
age: 18,
friend: ["Tom","john"]
}
var obj2 = Object.assign({},obj1,another);
console.log(obj2);
obj1.name = "信息技术协会";
obj1.sex.push("middle");
console.log(obj1);
</script>
复制代码
解释:
- 同样的目的,这个方法也只能实现浅拷贝,对于引用类型的拷贝,还是同样的道理,只是拷贝内存地址的指向。
- 这个方法有一个特点,就是如果后面的
...source
多个源对象中,如果存在有相同的属性,在拷贝完的目标对象中,只显示源对象中最后一个,也就是后面的对象会覆盖掉前面的。
笔试题:请问下面输出什么?
let a = {
name: 'nihao',
class: {
id: 12
}
};
let b = {
name: 'qietuzai',
class: {
type: 'leixing'
}
};
var c = Object.assign(a, b);
console.log(a, '我是a')
console.log(b, '我是b')
console.log(c, '我是c')
复制代码
解释:
- 这道题直接把
a
作为目标对象,所以要注意。- 如果存在有相同的属性,在拷贝完的目标对象中,只显示源对象中最后一个,也就是后面的对象会覆盖掉前面的。