谈谈浅拷贝和深拷贝的区别,以及实现的方法

两者的区别:一个对象浅复制后,是深层次的对象地址的复制,并没有开辟新的栈,也就是复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会发生改变,而深复制的则是开辟了一个新的栈,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。

话不多说,上代码:

// 原始对象
var obj = { 
	a:1, 
	arr: [2,3],
	say:function(){
		console.log('hello')
	},
	obj1:{
		arr:[34,55,5],
		hand:function(){
			console.log('hand')
		},
		obj3:{
			a:1,
			take:function(){
				console.log('take')
			}
		}
	}
};

// 开始浅复制
var shallowObj = shallowCopy(obj);

// 定义浅复制逻辑
function shallowCopy(src) {
  var dst = {};
  for (var prop in src) {
    if (src.hasOwnProperty(prop)) {
      dst[prop] = src[prop];
    }
  }
  return dst;
}

// 改变复制后的新对象属性值(第一层属性)
shallowObj.a = 2; 
shallowObj.arr = [9,8];
shallowObj.say = function(){
	console.log('world')
}

// 打印新对象的及方法
console.dir(shallowObj)    
shallowObj.say();  // world

// 打印原对象及方法
console.dir(obj);
obj.say();  // hello

结果如图所示:

谈谈浅拷贝和深拷贝的区别,以及实现的方法_第1张图片

结论 : 修改新对象的属性值,第一层的属性值的确没有变化,重点来了,我们给第二层以及更深层次的属性复制试试

// 原始对象
var obj = { 
	a:1, 
	arr: [2,3],
	say:function(){
		console.log('hello')
	},
	obj1:{
		arr:[34,55,5],
		hand:function(){
			console.log('hand')
		},
		obj3:{
			a:1,
			take:function(){
				console.log('take')
			}
		}
	}
};

// 开始浅复制
var shallowObj = shallowCopy(obj);

// 定义浅复制逻辑
function shallowCopy(src) {
  var dst = {};
  for (var prop in src) {
    if (src.hasOwnProperty(prop)) {
      dst[prop] = src[prop];
    }
  }
  return dst;
}

// 改变复制后的新对象的属性值(第二层以及更深层次)
shallowObj.obj1.obj3.take = function(){
	console.log('shallowObj_take') 
}
shallowObj.obj1.hand = function(){
	console.log('shallowObj_hand')
}

// 打印新对象的方法调用
shallowObj.obj1.obj3.take();  // shallowObj_take
shallowObj.obj1.hand();      // shallowObj_hand

// 打印原对象的方法调用
obj.obj1.obj3.take();   // shallowObj_take
obj.obj1.hand();     // shallowObj_hand

问题出现了:原对象的方法被新对象的修改,而产生变化。
原因是复制的是对象的地址指针,两个属性共同指向一个对象,只要其一发生变化,另一个也随之变化

深拷贝的方法:

1.可以递归递归去复制所有层级属性

// 原始对象
var obj = { 
	a:1, 
	arr: [2,3],
	say:function(){
		console.log('hello')
	},
	obj1:{
		arr:[34,55,5],
		hand:function(){
			console.log('hand')
		},
		obj3:{
			a:1,
			take:function(){
				console.log('take')
			}
		}
	}
};

// 深复制逻辑(递归调用)
function deepClone(obj){
    let objClone = Array.isArray(obj)?[]:{};
    if(obj && typeof obj==="object"){
        for(key in obj){
            if(obj.hasOwnProperty(key)){
                //判断obj子元素是否为对象,如果是,递归复制
                if(obj[key] && typeof obj[key] ==="object"){
                    objClone[key] = deepClone(obj[key]);
                }else{
                    //如果不是,简单复制
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}    

// 开始深复制
var shallowObj = deepClone(obj);

// 改变复制后的新对象的属性值(第二层以及更深层次)
shallowObj.obj1.obj3.take = function(){
	console.log('shallowObj_take') 
}
shallowObj.obj1.hand = function(){
	console.log('shallowObj_hand')
}

shallowObj.obj1.obj3.take();  // shallowObj_take
shallowObj.obj1.hand();      // shallowObj_hand

obj.obj1.obj3.take();   // take
obj.obj1.hand();     // hand

结论:深拷贝后改变对象的属性值,不会影响原始对象的值。

2.除了递归,我们还可以借用JSON对象的parse和stringify

function deepClone(obj){
    let _obj = JSON.stringify(obj),
            objClone = JSON.parse(_obj);
    return objClone
}    
let a=[0,1,[2,3],4],
    b=deepClone(a);
a[0]=1;
a[2][0]=1;
console.log(a,b);

3.除了上面两种方法之外,我们还可以借用JQ的extend方法

$.extend( [deep ], target, object1 [, objectN ] )

deep表示是否深拷贝,为true为深拷贝,为false,则为浅拷贝

target Object类型 目标对象,其他对象的成员属性将被附加到该对象上。

object1  objectN可选。 Object类型 第一个以及第N个被合并的对象。 


let a=[0,1,[2,3],4],
    b=$.extend(true,[],a);
a[0]=1;
a[2][0]=1;
console.log(a,b);


你可能感兴趣的:(javascript)