不管是深拷贝,还是浅拷贝都是针对复杂数据类型的,例如:Array,Object.
如果之前并没有听说过,深拷贝,浅拷贝,或者说的只是停留在听过的层次上,那么我们暂且先抛开什么深拷贝,浅拷贝不谈,先通过一个例子来实现以下对象属性的复制。
var obj1 = { name: 'zs', age: 18, sex: '男' } var obj2 = {}; // 遍历对象中的成员 for (var key in obj1) { obj2[key] = obj1[key]; } obj1.name = 'xx'; // 修改obj1的成员,此时不会影响obj2通过上面的代码我们已经成功把obj1对象中的属性,拷贝到obj2对象上了,更改各自属性不会对对方产生印象,但这样的写法不够灵活,需要我们把他封装成函数。
// 封装函数 - 把o1 的成员 , 复制给o2 function copy(o1, o2) { for (var key in o1) { o2[key] = o1[key]; } }
这样我们通过调用copy函数,将参数传进去就可以实现对象的复制,但这并不是我们想要的。大家可以想一下如果obj1对象中的一个属性,同时又是一个Object类型,或者Array,又有属于自己的属性或者值,那么上面的方法能不能帮助我们解决问题呢?接下来我们看一下这个问题。
// 对象的拷贝 var obj1 = { name: 'zs', age: 18, sex: '男', dog: { // 此时obj1又多了一个属性,这个属性同时也有自己的属性。 name: '金毛', age: 2, yellow: '黄色' } } var obj2 = {}; // 浅拷贝 function copy(o1, o2) { for (var key in o1) { o2[key] = o1[key]; } } copy(obj1, obj2); // 修改obj1中的成员 obj1.name = 'xxxx'; obj1.dog.name = '大黄'; console.log(onbj2) // 此时 obj2.dog.name = '大黄'
上的方法虽然可以对象的属性进行拷贝,但只是对对象的属性依次进行复制,并不会进行递归复制,而JavaScript中对象都是存储的地址,因此只是对地址进行复制,所以才会出现上面的现象,更改obj1中的dog的属性,会使obv2也受影响。为了更好的解决问题单单依靠浅拷贝是不行的。
var obj1 = { name: 'zs', age: 18, dog: { name: '大黄', age: 2, color: 'yellow' }, firends: ['ll', 'hmm'], } // 深拷贝 function deepCopy(o1, o2) { var o2 = o2 || {}; for (var k in o1) { if (typeof o1[k] === 'object') { o2[k] = o1[k] instanceof Array ? [] : {}; // 这里需要判断Array,因为数组也是Object(要先判断范围小的) deepCopy(o1[k], o2[k]) // 通过递归对对象属性进行深层拷贝 } else { o2[k] = o1[k] } } return o2 } var obj2 = deepCopy(obj1); obj2.dog.name = 'aaaaaaaaaaaaa' console.dir(obj1.dog.name) // '大黄' console.dir(obj2.dog.name) // 'aaaaaaaaaaaaa'
此时不仅可以对多层属性进行拷贝,并且对拷贝出来的对象属性进行更改不会影响原对象属性。是因为深拷贝,它不仅对原对象的各个属性逐个进行复制,而且对原对象各个属性所包含的对象也依次采用深拷贝的方法递归复制到新对象上。这就不会存在上面 obj1 和 obj2 的 dog 属性指向同一个对象的问题。
总结: 浅拷贝就是复制一份引用,所有引用对象都指向一份数据,并且都可以修改这份数据。
深拷贝则是复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。