深拷贝和浅拷贝的区别是什么?如何实现?
深拷贝和浅拷贝概念- 浅拷贝:只是拷贝了基本类型的数据,而引用类型数据,复制后也是会发生引用,我们把这种拷贝叫做浅拷贝(浅复制)。浅拷贝只复制指向某个对象的指针(引用地址),而不复制对象本身,新旧对象还是共享同一块内存。
- 深拷贝: 在堆中重新分配内存,并且把源对象所有属性都进行新建拷贝,以保证深拷贝的对象的引用图不包含任何原有对象或对象图上的任何对象,拷贝后的对象与原来的对象是完全隔离,互不影响.
浅拷贝的方法:
- 直接赋值
/** 1. 直接赋值 */
var obj1 = {
name : 'zhangsan',
age : 18,
hobby : {
fottball : 5
}
}
var obj2 = obj1;
obj1.name = 'lisi';
obj2.age = 20;
obj2.hobby.fottball = 10;
console.log(obj1);
console.log(obj2);
2.Object.assign 方法
/** 2. Object.assign 方法 */
var obj1 = {
name : 'zhangsan',
age : 18,
hobby : {
fottball : 5
}
}
var obj2 = Object.assign({} , obj1);
obj1.age = 20;
obj2.name = 'lisi';
obj2.hobby.fottball = 20;
console.log(obj1);
console.log(obj2);
- 使用 es6 的扩展运算符
/** 3. ES6的扩展运算符 */
var obj1 = {
name : 'zhangsan',
age : 18,
hobby : {
fottball : 5
}
}
var obj2 = {...obj1};
obj1.name = 'lisi';
obj2.age = 20;
obj2.hobby.fottball = 20;
console.log(obj1);
console.log(obj2);
- 数组的 slice 和 concat 方法
concat:
/** 4.数组的slice 和 concat 方法 */
var arr1 = [1, 3, 'str', {name: 'zhangsan'}];
var arr2 = arr1.concat();
arr1[0] = 2;
arr2[2] = 'arr';
arr2[3].name = 'lisi';
console.log(arr1);
console.log(arr2);
slice:
var arr1 = [1, 3, 'str', {name: 'zhangsan'}];
var arr2 = arr1.slice();
arr1[0] = 2;
arr2[2] = 'arr';
arr2[3].name = 'lisi';
console.log(arr1);
console.log(arr2);
- jquery 中的 extend 方法
/** 5.jquery 的 extend 函数
* $.extend() 里面有三个参数,第一个参数 true 为深拷贝,false为浅拷贝, 第二个参数是要拷贝的对象,第三是被拷贝的对象
* 第一个参数默认是 false ,即默认是浅拷贝
*/
var obj1 = {
name : 'zhangsan',
age : 18,
hobby : {
fottball : 5
}
}
var obj2 = {};
$.extend(obj2 , obj1);
obj2.age = 20;
obj2.hobby.fottball = 20;
console.log(obj1);
console.log(obj2);
深拷贝的方法:
1.JSON.parse(JSON.stringify())
var obj1 = {
name : 'zhangsan',
age : 18,
hobby : {
fottball : 5
}
}
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.age = 20;
obj2.hobby.fottball = 20;
console.log(obj1);
console.log(obj2);
但是这种方法有缺陷,JSON.parse 和 JSON.stringify 原本是处理 JSON对象的,JSON对象没有函数类型,因此若对象里面有函数,用该方法会丢失函数,如下所示:
var obj1 = {
name : 'zhangsan',
age : 18,
hobby : {
fottball : 5
},
sayHi : ()=>{
console.log(this.name)
}
}
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.age = 20;
obj2.hobby.fottball = 20;
console.log(obj1);
console.log(obj2);
- 使用 jquery 的 extend 方法
/** 深拷贝 2.jquery 的 extend 函数
* $.extend() 里面有三个参数,第一个参数 true 为深拷贝,false为浅拷贝, 第二个参数是要拷贝的对象,第三是被拷贝的对象
* 第一个参数默认是 false ,即默认是浅拷贝
*/
var obj1 = {
name : 'zhangsan',
age : 18,
hobby : {
fottball : 5
}
}
var obj2 = {};
$.extend(true , obj2 , obj1);
obj2.age = 20;
obj2.hobby.fottball = 20;
console.log(obj1);
console.log(obj2);
3.手写深度拷贝递归函数
var obj1 = {
name : 'zhangsan',
age : 18,
hobby : {
fottball : 5
}
}
function deepClone(target){
var result; // result : 要返回的深度克隆后的对象
if(typeof target === 'object'){
if(Array.isArray(target)){
// target 对象是数组
result = [];
for(let i in target){
result.push(deepClone(target[i]));
}
}else if(target === null){
// target 为 null , 值为 null 的变量 typeof 也为 object
result = null;
}else if(target.constructor === RegExp || target.constructor === Date){
//target 为正则表达或Date , 这两种的 typeof 也为 object
result = target;
}else{
//进入该分支,表明target 是一个对象
result = {};
for(let i in target){
result[i] = deepClone(target[i]);
}
}
return result;
}else{
// 进入此分支,代表 target 是 number ,string ,booblean 一类的原始值,因此直接赋值就可
result = target;
return result;
}
}
var obj2 = deepClone(obj1);
obj2.age = 20;
obj2.hobby.fottball = 20;
console.log(obj1);
console.log(obj2);