面试官:浅拷贝与深拷贝

191 阅读2分钟

浅拷贝与深拷贝

深拷贝与浅拷贝是对于引用型数据而言的,对于简单数据类型不存在这个问题。这个问题的根源还要从内存的存储机制说起。

存储方式

我们都知道在计算机中的内存中,分为栈存储空间与堆存储空间。简单数据类型与复杂数据都会存放在栈空间中,只不过,简单数据类型在栈中直接存储数据值,而复杂数据类型则会在堆空间中开辟一块地址,用力存储真实的数据,在栈中只存储一个地址,用于指向这片堆空间。

20190807124454949.png

浅拷贝

对于简单数据类型,我们直接在栈空间中,将其的数据进行修改,因此不存在深浅拷贝的问题。但是对于负责类型则不然,复杂类型的赋值就修改栈空间中的地址指向,如下图,两个数组会指向同一片堆空间,这就是浅拷贝,当我们操作其中一个数组时,会影响到另一个数组,因为两者本质上指向同一片存储空间,数据是共享的。

20190807125004719.png

深拷贝

那么我们如何进行深拷贝,从而让两个复杂数据类型互不干扰呐?或许,有些人的第一想法是将复杂数据类型中的每一个键值对分别拷贝新的数据。没错,这样确实可以实现深拷贝,那么如果键值对中的数据又是一个对象呐?或许,可以再进行一次上述操作。是的,这就是深拷贝的初级想法,代码及内存图如下:

20190807125947792.png

其实,我们还可以让代码更加优雅一些,利用递归函数来实现上述思想:

1、递归函数实现深拷贝

var p = {
	"id":"007",
	"name":"刘德华",
	"wife":{
		"id":"008",
		"name":"刘德的妻子",
		"address":{
			"city":"北京",
			"area":"海淀区"
		}
	}
}
 
//写函数
function copyObj(obj){
	let newObj={};
	for(let key in obj){
		if(typeof obj[key] =='object'){//如:key是wife,引用类型,那就递归
			newObj[key] = copyObj(obj[key])
		}else{//基本类型,直接赋值
			newObj[key] = obj[key];
		}
	}
	return newObj;
}
 
let pNew = copyObj(p);
pNew.wife.name="张三疯";
pNew.wife.address.city = "香港";
console.log(pNew);
console.log(p);

2、用JSON来实现深拷贝

除此之外,我们还可以使用JSON来实现:

var obj = {
  a: {
    c: 2,
    d: [9, 8, 7]
  },
  b: 4
}
var jsontext = JSON.stringify(obj)
var obj1 =JSON.parse(jsontext) 
console.log(obj);
console.log(obj1);

obj.a.d[0] = 666

console.log(obj);
console.log(obj1);

3、cloneDeep方法来实现

使用lodash函数库中的cloneDeep方法来实现(lodash中的cloneDeep)

var _ = require('lodash')

var obj = {
  a: {
    c: 2,
    d: [9, 8, 7]
  },
  b: 4
}

var obj1 = _.cloneDeep(obj)

console.log(obj === obj1);//false