浅克隆:克隆的时候没有创建新对象,还是共用原来的地址,克隆出来的对象跟着一起变化。
/*浅克隆*/
var arr=[1,2,3,4,5];
var arr2=arr;
arr[0]=100;
console.log(arr2); //[100, 2, 3, 4, 5]
深克隆:克隆的时候创建了一个新对象,不再共用地址,克隆出来的对象不跟着一起变化。
/*深克隆封装*/
function deepClone(origin,target){
var target = target || {},
toStr = Object.prototype.toString,
arrType = '[object Array]';
for(var prop in origin){
if (origin.hasOwnProperty(prop)) {
if (origin[prop] !== 'null' && typeof origin[prop] === 'object') {
if (toStr.call(origin[prop]) == arrType) {
target[prop] = [];
}else{
target[prop] = {};
}
deepClone(origin[prop],target[prop]);
}else{
target[prop] = origin[prop];
}
}
}
}
var obj = {
name : 'syy',
age : 12,
tabs : [1,2,3,4,5],
hobbies : {
a : 'a',
b : [4,5,6,7],
c : {
d : 'd',
e : 'e'
}
}
}
var obj1 = {};
deepClone(obj,obj1)
obj.tabs[0]=100;
obj.hobbies.c.d="wxy";
console.log(obj1); //obj1打印出来的值见下图
有些文章说到深拷贝时说,用slice、concat、扩展运算符也可实现,这是个很大的误区。写个简单的demo,乍一看,很有道理,这里边却有个不易察觉的误区:
var a = [1,2,3];
var b = a.slice(0);
var c = a.concat();
b.push(4);
c.push(5);
var d = [...a];
console.log(a); // [1,2,3]
console.log(b); // [1,2,3,4]
console.log(c); // [1,2,3,5]
console.log(d); // [1,2,3]
看到上述打印结果,大家一定以为这么容易就能实现深克隆,上面深克隆的封装还巴拉巴拉写辣么多,装13的么?别急,且往下看,稍微变点形式,就能看出差别了:
var a = [1,2,3,[6,7]];
var b = a.slice(0);
var c = a.concat();
b[3][0] = 100;
c.push(5);
var d = [...a];
console.log(a); // [1,2,3,[100,7]]
console.log(b); // [1,2,3,[100,7]]
console.log(c); // [1,2,3,[100,7],5]
console.log(d); // [1,2,3,[100,7]]
可以看到,silce、concat、扩展运算符的写法,外面的引用不共用地址,深层的元素引用却还是共享一个地址。不知道这个小知识点,写项目的时候这个bug少说要花费一两个小时呦!
结论:slice、concat、扩展运算符仅适用于不包含引用对象的一维数组的深拷贝。