我们都知道,数据的存储是栈或者堆,栈中一般存储的是基本类型的数据,比如Boolean、String、Number、undefined、null,这些数据是已知大小或有范围上限的,属于一种简单存储;而堆中一般储存的数据是object类型的,这种数据往往大小未知,储存需要很大的内存空间,往往这类数据都是引用地址存储,也就是说当调用此类数据时,先得去栈中找引用地址命名的变量,通过变量名去调用它的方法。
同时,也就有了对象深浅复制的概念。浅复制就是说在复制完成之后,由于其引用地址未变,当改变旧值时新对象中的值也会变;深复制就是复制完之后,新对象和旧对象没有引用关系,改变旧值不会影响新值,下面我们来看看具体是怎么样进行深浅复制的。
1、for-in浅拷贝(遍历对象)
var obj = {
a:1,
b:2,
c:{
d:2,
e:5
}
}
var obj1 = {};
for(var i in obj){
obj1[i] = obj[i];
}
obj.a= 4;
console.log(obj1.a);//1
obj.c.d= 4;
console.log(obj1.c.d);//4
说明:此方法只能遍历第一层,也就是说除第一层不是引用地址赋值之外,内层的依然是。
2、JSON的深拷贝
var obj = {
a:1,
b:2,
c:{
d:2,
e:function(){
console.log("a");
}
}
}
var obj1 = JSON.parse(JSON.stringify(obj));
obj.c.d = 10;
console.log(obj1.c.d);//2
说明:JSON方法随好用,代码也简短,但是JSON不能拷贝方法,也就是说当原对象中有方法时,无法通过此方法复制对象,有缺陷。
3、递归实现简单数据类型的深复制
function cloneObj(obj,target){
target = target || {};
for(var prop in obj){
if(typeof obj[prop] === "object" && obj[prop] !==null){
target[prop] = {};
cloneObj(obj[prop],target[prop]);
}else{
target[prop] = obj[prop];
}
}
return target;
}
4、升级版的递归
function cloneObj(source,target){
var names = Object.getOwnPropertyNames(source);
for(var i = 0;i < names.length;i++){
var desc = Object.getOwnPropertyDescriptor(source,names[i]);
if(typeof desc.value === "object" && desc.value !== null){
var obj;
switch(true){
case desc.value.constructor === Date:
obj = new Date(desc.value.toString());
break;
case desc.value.constructor === RegExp:
obj = new RegExp(desc.value.source,desc.value.flags);
break;
case HTMLElement.isPrototypeof(desc.value.constructor):
obj = document.createElement(desc.value.nodeName);
break;
default:
obj = new desc.value.constructor;
}
Object.defineproperty(target,names[i],{
configurable:desc.configurable,
enumerable:desc.enumerable,
writable:desc.writable,
value:obj
})
cloneObj(desc.value,obj);
}else{
Object.defineproperty(target,names[i],desc);
}
}
return target;
}
说明:此方法y存在缺陷,函数(方法)不能复制。
以上内容有不对的还请多指正!