引言
要介绍深浅拷贝那么咱们先了解一下js的数据类型。
- 基本数据类型:number,string,boolean,undefined,null
- 复杂数据类型:object,array,function,regexp,date 等
一、简介
1.浅拷贝
对于基本数据类型,浅拷贝相当于直接赋值
对于复杂数据类型,浅拷贝只拷贝一层,相当于只拷贝其引用,例如对象B是由对象A浅拷贝得到的,即AB还是指向内存中的同一地址
,那么改变对象B,对象A也会改变
2.深拷贝
对于复杂数据类型,深拷贝会拷贝多层,是真正意义上的拷贝,例如对象B是由对象A深拷贝得到的,即AB指向
不同的内存地址
,那么无论如何改变对象B,对象A也不会改变
二、实现方法
上面讲完什么是深浅拷贝,那么接下来就用具体的代码去实现深浅拷贝
1.浅拷贝
方法一:简直粗暴的直接赋值
var obj1 = { name: 'ming', age: 10 };
var obj2 = obj1;
obj2.name = 'lei';
console.log(obj1.name) // lei
console.log(obj2.name) // lei
方法二:Object.assign(target,source) ES6
Object.assign方法实行的是浅拷贝,而不是深拷贝。如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用,如下面的例子
var obj1 = { name: 'father', children: {name:'son',age:10} };
var obj2 = Object.assign({},obj1)
obj2.children.name = 'lei';
console.log(obj1.children.name) // lei
console.log(obj2.children.name) // lei
方法三:for in 循环
和方法二类似,如果源对象的某个属性是对象,那么目标对象拷贝得到的是这个对象的引用
var obj1 = { name: 'father', children: {name:'son',age:10} };
var obj2 = {};
for (var key in obj1){
obj2[key] = obj1[key];
}
obj2.children.name = 'lei';
console.log(obj1.children.name) // lei
console.log(obj2.children.name) // lei
方法四:Object.create(target,source);
Object.getOwnPropertyDescriptors
为 ES6 新增方法
var obj1 = { name: 'father', children: {name:'son',age:10} };
var obj2 = Object.create({}, Object.getOwnPropertyDescriptors(obj1));
obj2.children.name = 'lei';
console.log(obj1.children.name) // lei
console.log(obj2.children.name) // lei
2.深拷贝
方法一:JSON.parse(JSON.stringify(source))
用JSON.stringify将源对象(source)转为字符串,再用JSON.parse方法将字符串转为目标对象
注:
此方法只能用作可以转为JSON格式对象,否则JSON.stringify方法将会报错,并且不管原来对象的构造函数是什么拷贝之后都会变为Object
var obj1 = { name: 'ming', age: 10 };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = 'lei';
console.log(obj1.name) // ming
console.log(obj2.name) // lei
方法二:递归拷贝
function deepClone(obj1, obj2) {
var obj = obj2 || {};
for (var i in obj1) {
var temp = obj1[i]; // 避免相互引用对象导致死循环,如obj1.a = obj1的情况
if (temp === obj) {
continue;
}
if (typeof temp === 'object') {
obj[i] = (temp.constructor === Array) ? [] : {};
arguments.callee(temp, obj[i]);
} else {
obj[i] = temp;
}
}
return obj;
}
var obj1 = { name: 'father', children: {name:'son',age:10} };
var obj2 = deepClone(obj1);
obj2.children.name = 'lei';
console.log(obj1.children.name) // son
console.log(obj2.children.name) // lei
方法三:Object.create()
function deepClone(obj1, obj2) {
var obj = obj2 || {};
for (var i in obj1) {
var temp = obj1[i]; // 避免相互引用对象导致死循环,如obj1.a = obj1的情况
if (temp === obj) {
continue;
}
if (typeof temp === 'object') {
obj[i] = (temp.constructor === Array) ? [] : Object.create(temp);
} else {
obj[i] = temp;
}
}
return obj;
}
var obj1 = { name: 'father', children: {name:'son',age:10} };
var obj2 = deepClone(obj1);
obj2.children.name = 'lei';
console.log(obj1.children.name) // son
console.log(obj2.children.name) // lei
方法四:Object.assign(target,source) ES6
将源对象(source)的所有可枚举属性,复制到目标对象(target)
注:
此方法只能用作对象只有一层的情况
var obj1 = { name: 'ming', age: 10 };
var obj2 = Object.assign({},obj1);
obj2.name = 'lei';
console.log(obj1.name) // ming
console.log(obj2.name) // lei
但是,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用,因此也不能被称为深拷贝
var obj1 = { name: 'father', children: {name:'son',age:10} };
var obj2 = Object.assign({},obj1)
obj2.children.name = 'lei';
console.log(obj1.children.name) // lei
console.log(obj2.children.name) // lei
方法五:for in 循环
注:
此方法只能用作对象只有一层的情况,类似方法三
var obj1 = { name: 'ming',age:10};
var obj2 = {};
for (var key in obj1){
obj2[key] = obj1[key];
}
obj2.name = 'lei';
console.log(obj1.name) // ming
console.log(obj2.name) // lei
实现浅拷贝的方法还有很多种,但是真正实现深拷贝的方法却很少,所以在拷贝对象时一定要注意
网友评论