闲话
回看一个多月都没写博客了,最近在忙于给新人交接,其中就遇到了深拷贝的问题。今天抽空来聊聊深拷贝与浅拷贝。
引子
Js里有两种数据类型,基本数据类型和引用数据类型。深拷贝、浅拷贝一般都是针对引用数据类型的。
请看代码:
var a = 1;
var b = a;
a = 2;
console.log(a); // 2
console.log(b); // 1
对于基本数据类型赋值操作,b 复制了 a 的值,而不是引用。即保存 b 的值与 a 的值的内存空间是完全独立的。
var arr1 = [1,2,3,4];
var arr2 = arr1;
arr1.push(5);
console.log(arr1); // [1,2,3,4,5]
console.log(arr2); // [1,2,3,4,5]
arr2.push(6);
onsole.log(arr1); // [1,2,3,4,5,6]
console.log(arr2); // [1,2,3,4,5,6]
然而,对于引用数据类型的赋值操作,arr2 仅仅是复制了 arr1的引用(也可以称之为指向 arr1 内存地址的指针)。简单来说,就是 arr1 与 arr2 指向了同一个内存空间。
正题
浅拷贝
概念:浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。
例:
/*
* copyTarget:要拷贝的对象
*/
function shallowCopy(copyTarget) {
var obj = {};
for (var key in copyTarget) {
obj[key] = copyTarget[key];
}
return obj;
}
var json1 = {
'name': '张三',
'family': {
'children': '张三三','wife': '李四'
}
}
var json2 = shallowCopy(json1);
// before
console.log(json2);
// after
json1.family['father'] = '张一'
console.log(json1);
console.log(json2);
由此可以看出,浅拷贝仅仅拷贝了基本类型的数据,对于引用类型数据,则指向被复制的内存地址,若原地址中的对象发生改变,那么浅复制出来的对象也会相应改变。
深拷贝
有了浅拷贝的理解,那么深拷贝可概括为:为引用类型数据成员另辟了一个独立的内存空间,实现真正内容上的拷贝。
例:
/*
* copyTarget:要拷贝的对象
*/
function deepCopy(copyTarget) {
var obj = {};
for(var key in copyTarget) {
// 先判断obj[key]是否为对象
if(typeof copyTarget[key] === "object"){
// 递归
obj[key] = deepCopy(copyTarget[key]);
} else {
// 如果不是对象,直接赋值即可
obj[key] = copyTarget[key];
}
}
return obj;
}
var json1 = {
'name': '张三',
'family': {
'children': '张三三','wife': '李四'
}
}
var json2 = deepCopy(json1);
// before
console.log(json2);
// after
json1.family['father'] = '张一'
console.log(json1);
console.log(json2);
拓展
深复制可以用JSON的方式:JSON.parse(JSON.stringify(obj))
但是JSON复制会忽略掉值为undefined以及函数表达式。
例:
var obj = {
a: 1,
b: 2,
c: undefined,
sum: function() { return a + b; }
};
var obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2); //Object {a: 1, b: 2}