1 区别
浅拷贝
- 对于简单类型(数字、字符串、布尔),浅拷贝就是对值的拷贝
- 对于复杂类型(对象、数组、函数),浅拷贝是对地址的拷贝,并没有开辟新的栈
- 复杂类型拷贝的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会改变
深拷贝
- 深拷贝面向的是复杂类型
- 深拷贝会开辟新的栈,两个对象对应两个不同的地址
- 修改一个对象的属性,不会改变另一个对象的属性
- 真正的深拷贝一定要判断类型
- 需要注意的是,深拷贝不会拷贝原型__proto__
2 深拷贝方法
简单深拷贝
使用Object.assign()方法
//缺点是只能深拷贝第一层属性
let a={name:'frank',child:{name:'jack'}}
let b=Object.assign({},a)
使用es6的展开运算符
//缺点是只能深拷贝第一层属性
let a={name:'frank',child:{name:'jack'}}
let b={...a}
使用concat()方法
let a=[1,2,3]
let c=[];
let b=c.concat(a);
b.push(4);
console.log(b);//1,2,3,4
console.log(a)//1,2,3
使用slice()方法
let a=[1,2,3]
let b=a.slice(0);
b.push(4);
console.log(b);//1,2,3,4
console.log(a)//1,2,3
复杂深拷贝
使用JSON的stringify和parse方法
let a={name:1,child:{name:2}}
let b=JSON.parse(JSON.stringify(a))
使用递归
递归是从底层的角度来实现深拷贝的,它是通用的
var obj = {
arr1 : [1,2,3],
fn: function(){
console.log('我是一个方法')
},
a : '我是普通属性'
}
// 现在我要把obj字面量创建里的属性深拷贝( 属性值是引用类型也要深拷贝 )
function deepClone(obj){
// 根据类型制造一个新的数组或对象 => 指向一个新的空间
// 由于数组的typeof也是'object',所以用Array.isArray(obj)
var new_obj = Array.isArray(obj) ? [] : {};
// 首先判断obj的类型
// 普通类型
if( typeof obj != 'object' ){
// 这里不能直接返回obj,不然就是浅拷贝的性质
return new_obj = obj
}
//引用类型
//数组
if(obj instanceof Array ){
for(i = 0; i < obj.length; i++ ){
new_obj[i] = obj[i];
if(typeof new_obj[i] == 'object'){
deepClone(new_obj[i])
}
}
}else{ //对象
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 对象中的数组和对象
if (typeof obj[key] == 'object') {
new_obj[key] = deepClone(obj[key]);
}else{//对象中没有引用类型
new_obj[key] = obj[key]
}
}
}
}
return new_obj;
}
var deepClone = deepClone(obj);
console.log(deepClone);
// 测试是不是深拷贝
obj.fn = '我改变了方法属性';
console.log(obj); //{arr1: Array(3), fn: ƒ, a: "我是普通属性", c: "我新增了一个属性"}
console.log(deepClone); // 还是 {arr1: Array(3), fn: ƒ, a: "我是普通属性"}
通过jQuery的extend方法实现深拷贝
let array = [1,2,3,4]
let newArray = $.extend(true,[],array);