谈浅拷贝和深拷贝之前,先了解js中的值类型,我们知道的类型有Number、string、Array、Boolean、Object、null、undefined、Function,其中基础类型包括Number 、string、Boolean、null、undefined,他们是按值访问的,我们可以直接操作保存在变量中的值。引用类型包括Array、Object、Function,他们的值是存在堆内存中的,js不允许直接访问,只能通过引用访问。
例如我们定义一个a:
var a = 1;
那么js会在栈内存分配出空间,存放a和值1
var b = a;
这时,栈内存会再分配出新的空间,来存放b和值1
name | value |
a | 1 |
b | 1 |
a和b是互相独立的,所以
a = 10;
console.log(a,b) // 10,1
我们再定义一个对象obj1:
var obj1 = {
name: 'tom',
age: 24
}
这里js会把obj1存放到栈内存中去,把值放到堆内存中,我们只能通过obj1来获取到值,可以理解为obj1存放了一个指针,指向堆中值所在的位置
var obj2 = obj1;
这时,只是把obj1的指针赋给了obj2
栈 | 堆 | |
obj1 | 指针(堆地址) | name: 'tom', age: 24 |
obj2 | 指针(堆地址) |
当我们更改obj1对象的值时,obj2就会同时变化,因为他俩是一个对象。。。这种情况就是所谓的浅拷贝了
那么怎样才能实现把obj1对象赋值给一个新的对象呢?这就是要说的深拷贝
我们可以试着定义一个空的对象:
var obj2 = {}
把obj1中的属性照着添加就可以了,这样就是完全重新创建了一个对象
obj2.name = 'tom';
obj2.age = 24;
当然,一般对象中的属性很多,并且属性可能是引用类型的值,所以我们可以用函数按照这个思路来封装一下,用递归的方法来实现
function deepCopy(obj) {
let newObj = Array.isArray(obj)? [] : {};
if(obj && typyof(obj) == 'object'){
for(key in obj){
//因为对象会沿着原型链查找属性,所以这里判断是否是对象自己的属性是有必要的
if(obj.hasOwnProperty(key)){
//判断属性是否为对象
if(obj[key] && typeof(obj[key] === 'object')) {
newObj[key] = deepCopy(obj[key]);
}else{
//否则就直接简单赋值
newObj[key] = obj[key]
}
}
}
}
return newObj;
}
除了递归,我们还可以使用JSON对象的序列化和解析,也会返回一个新的对象
function deepCopy(obj) {
let a = JSON.stringify(obj);
let b = JSON.parse(a);
return b;
}
当然,在学习jquery的时候,jquery也提供了一个全局方法$.extend()
$.extend(deep, target, object1[,objectN])
deep: boolean true是深拷贝,false是浅拷贝
target:新生成的对象
object1 objectN: 要被合并的对象
好了,那么在实际开发中,当我们每次从服务器获取到返回值时,如果返回的是一个对象,而这个对象可能在多个地方要使用到,那么为了不影响其他函数使用,最稳妥的办法就是深拷贝一个新的对象,然后再使用。
那么,暂时就想到这些了