深拷贝和浅拷贝的知识涉及到堆栈的概念。

堆栈的概念:

基本类型:
名值存储在栈内存中,例如:

let a = 1;

引用类型:
名存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值;

总体来说就是栈内存中保持的是基本类型的值,引用类型的“引用”,堆内存中保存的是创建的对象实例。

浅拷贝:

b clone了 a
当修改a的时候,b也会发生改变
这就是浅拷贝。
但是基本类型不会受其影响:

let a = 2;
let b = a;
a = 3;
console.log(a, b)	//3,2

引用类型的数据就会受其影响:

let a = [0, 1, 2];
b = a;
a[0] = 3;
console.log(a, b)	//结果相同

深拷贝和浅拷贝_前端开发
特别注明: jQuery的extend默认是浅拷贝的方法

深拷贝和浅拷贝_JS_02
深拷贝和浅拷贝_前端开发_03

那么我们如何实现深拷贝呢?

1.使用递归去复制所有层级属性。
这里封装一个深拷贝的函数

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;
}
let a = [1,2,3,4],
	b = deepClone(a);
a[2]=100;
console.log(a,b)  //结果不同,b已经脱离a的控制了

深拷贝和浅拷贝_前端开发_04
这里再次强调,深拷贝是拷贝对象各个层级的属性!
我们在试一试数组的slice()方法:

t a = [1,2,3,4],
b = a.slice();
a[0] = 2;
console.log(a,b)  //不相同

深拷贝和浅拷贝_JS_05
slice()实现了深拷贝?
别着急下定论,我们在测试一下:

let a = [1,[2,3],4],
b = a.slice();
a[0]=3;
a[1][0]=4;
console.log(a,b)  //1级属性不相同,2级属性相同

深拷贝和浅拷贝_JS_06
所以slice()方法并不是真正的深拷贝。
第一层的属性确实深拷贝,拥有了独立的内存,但更深的属性却仍然公用了地址,所以才会造成上面的问题。同理,concat方法与slice也存在这样的情况,他们都不是真正的深拷贝。这里需要注意一下。

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

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

结果如下:
深拷贝和浅拷贝_前端开发_07
JSON.stringfly与JSON.parse除了实现深拷贝,还能结合localStorage实现对象数组存储。

3.除了上面俩种方法之外,我们还可以借用jQuery的extend方法
$.extend([deep],target,object1[,objectN])
deep表示是否深拷贝,为true为深拷贝,为false,则为浅拷贝
traget Object类型,目标对象,其他对象的成员属性将被附加到该对象上。
object1 objectN可选。 Object类型 第一个以及第N个被合并的对象。

代码如下:
深拷贝和浅拷贝_前端开发_08
结果如下:
深拷贝和浅拷贝_JS_09