深拷贝:复制出的新变量的改变不会影响原变量。
浅拷贝:复制出的新变量的改变会影响原变量。
js中实现深拷贝的几种方法和优缺点:
1手动实现(只使用于一层对象,实际是浅拷贝?)
function deepClone(obj,copy){
copy=copy||{};
for(var key in obj){
copy[key]=obj[key];
}
return copy;
}
2.将对象转换为一个json字符串再转换回来
function deepClone(obj,copy){
return JSON.parse(JSON.stringify(obj));
}
这种方法比较简单,但是也有一些缺点:
它只能处理能够被转换成json字符串的对象,例如Array,Number,Boolean,String,扁平对象,其它的比如function和RegExp对象无法被处理。
这样转换后,会丢掉原来对象的构造函数,不管这个对象原来的构造函数是什么,深拷贝之后都会转换成对象。
3.递归拷贝
function deepClone(obj){
if(typeof(obj)!='object'){
return obj;
}
var newObj=obj.constructor==Array?([]):({});
for(var i in obj){
newObj[i]=deepClone(obj[i]);
}
return newObj;
}
这种递归和上面的json序列化反序列化都无法处理一种情况,就是当对象存在循环引用的情况
什么是循环引用呢?
var obj1 = {
a: 1,
}
obj1.b = obj1;
当对象存在循环引用的时候,可以这样写
function deepClone (obj) {
var arr1 = [];
var arr2 = [];
function _deepClone (obj) {
if(!obj) {
return null;
}
var newObj = {};
var index = arr2.indexOf(obj);
if(index != -1) { // 如果父数组存在本对象,说明之前已经被引用过,直接返回此对象
return arr1[index];
}
arr1.push(newObj);
arr2.push(obj)
for(var key in obj) {
newObj[key] = _deepClone(obj[key]);
}
return newObj;
}
return _deepClone(obj);
}
4.ES6 ...运算符方法实现
function deepClone(obj){
var {...obj2}=obj;
return {...obj2};
}
5.ES6 Object.assign()方法
function deepClone(obj){ //只适用于有一层对象
var obj2={};
obj2=Object.assign(obj2,obj);
return obj2;
}
但是这个方法只适用于只有一层对象