为什么会有深拷贝和浅拷贝,以及深拷贝的应用场景就这里就不过多的描述了,网络上一大堆,直接贴代码:
function deepCopy(obj, par) { if(typeof obj !== 'object') return obj; var result = par || {}; for(key in obj) { if(obj.hasOwnProperty(key)) { // 只遍历私有的属性 var cur = obj[key]; if(typeof cur === 'object') { // 如果是引用数据类型的 if(cur instanceof Array) { // 如果是个数组 result[key] = []; } else { result[key] = {}; } arguments.callee(cur, result[key]); } else { result[key] = cur; } } } return result; }
如果当前要进行拷贝的这一项如果是 object 类型的,那么就继续判断是哪一个,这里暂且只处理数组和对象。
假如有这么一个对象吧:
var exp = { age: 10, obj: { a: 1, b: 2, c: [1, 2, 3] } };
当 key 到 obj 的时候,就会进入对 object 类型值的处理逻辑,这里 obj 是一个对象,所以需要给 result 添加一个同样名为 obj 的属性,这个属性的值是一个空对象( result.obj = {} );
由于这是一个对象,所以我们还需要再把其中的每一项都给拿出来,所以递归调用,第一个参数是要处理的对象,第二个参数就是要操作的当前项。
拆分下:
1、要处理的对象,每个对象和数组我们都要深拷贝,所以每个对象下面的数组和对象,以及每个数组下面的数组与对象,都需要逐个的拆分出来。
2、操作当前项:
如果这个参数不存在就表示当前的深度处于最浅的层,也就是处于和 exp 下面的 age 同级层。也可以理解为这个函数执行不是被递归调用的。
在对 exp.obj 处理时,代码会先给 result 添加一个名为 obj 的空对象然后重新调用一次方法,deepCopy(exp.obj, result.obj),这里面实际上传的是 exp.obj 和 {} 所对应的内存指向;
因为传过去的不管是空对象还是空数组,都是引用数据类型,所以递归处理的时候给对象添加的属性是直接可以改变之前声明的属性的。
这样就完成了一个简单的深拷贝。
再放一个简单优化了一下的代码,没怎么测试,参考一下就行:
感觉这样才没有浪费函数的 return 啊,哈哈哈。
function deepCopy(obj) { if(typeof obj !== 'object') return obj; var result = obj instanceof Array ? [] : {}; for(key in obj) { if(obj.hasOwnProperty(key)) { var cur = obj[key]; result[key] = typeof cur === 'object' ? arguments.callee(cur) : cur; } } return result; }
为什么说是简单的深拷贝?
因为这里面考虑的地方非常的不全面,还有很多的细节没有处理,不过这也足够满足日常的需求了。
如果以后继续深入研究有什么新收获的话,会继续更新。