我们都知道在js中,关于基本类型(Number、String 、Boolean、Null和Undefined)是按值访问的,因此可以直接操作保存在变量中的实际值,存在栈当中
var b ;
var a = 10;
b = a;
a与b的值是相互独立的,在复制的过程中同时也新创建了一个内存给他使用。
但是引用类型(Object 、Array 、Function 、Data),他们是存储在堆当中的,相应变量存储的是你的引用对象在堆当中的地址,通过这个地址进行快速的访问。
var obj1 = new Object();
var obj2 = obj1;
obj2.name = "我有名字了";
console.log(obj1.name); // 我有名字了
OK,这两种类型也造成了我们的问题,浅拷贝与深拷贝;
浅拷贝:顾名思义就是比较浅的复制,在拷贝对象的过程当中,对于基本类型我们能得到正确的值,而对于引用类型我们只能够得到一个地址,这也就造成了,我们复制出来的对象有一部分和另外一个对象公用了某一部分,这显然是我们不想要的(除非你就想要这么做,whatever)。So,就有了我们的深拷贝,深拷贝就是要避免这类问题的出现确保每一次的拷贝都能够完全产生一个新的对象,他们互不干扰;
那么怎么实现深拷贝呢?
先来一种最简单的实现方式,可以说是非常便捷了就是JSON.stringify()与JSON.parse();对于一个我们要复制的对象(obj1),像下面这样就能够完成深拷贝:
var obj2 = JSON.parse(JSON.stringify(obj1));
JSON.stringify()会把我们的obj1序列化成字符串,这样即使是引用类型也会被序列化出来,再通过JSON.parse()解析这样一个JSON字符串,我们就可以重新得到一个对象了,而其中的内容都是新创建的与原来的对象是独立的,在我们需要拷贝的对象比较simple的时候这样做是比较简单、省力的,但这样也会存在一些问题,
1. function拷贝不过去
2. 没有层次控制,如果对象的层次结构很深,会一直往下走,有性能问题;
OK,那么还有其他方法吗?有啊:
1. jQuery的extentd实现深拷贝
假设有一个接收对象var target = {},要复制的对象source;使用jQuery.extend(true , target , source)即可完成深拷贝;
2. 我们自己来实现一个深拷贝
自己实现深拷贝注意的点,需要有类型检测,因为typeof []返回的是“array”,{}返回的也是“array”,而我们对数组和对象当然需要有不同的操作;
OK,首先先来实现一个类型判断函数
var isType = function(obj,type){
return Object.prototype.toString.call(obj) === "[object "+type+"]";
}
接下来我们就开始写我们的深拷贝函数
var deepCopy = function(source){
var result = {};
for(key in source){
//如果是数组类型
if(isType(source[key] , "Array")){
result[key] = source[key].slice(0);
}else if(isType(source[key] , "Object")){
result[key] = deepCopy(source[key]||{});
}else{
result[key] = source[key]
}
}
return result;
}
OK,深浅拷贝暂时就到这里了,如果有什么不对的地方记得指出来哦(●’◡’●)
参考:
1. https://yq.aliyun.com/articles/35053
2. http://www.jquery123.com/jQuery.extend/