开发过程中,有时会遇到把现有的一个对象的所有成员属性拷贝给另一个对象的需求,这就是拷贝。接下来我们就来讲讲JavaScript里面的拷贝。在JavaScript中,将我们的拷贝分为两类,一类是深拷贝,还有一类是浅拷贝。 那么怎么区分深拷贝和浅拷贝呢? 浅拷贝就是直接将一个Object对象所有的属性和属性值复制给另一个Object对象。这样导致的后果是,新对象和老对象相同的Object类型的属性值在内存中的指向是一样的,也就是新对象和老对象的Object类型的同一属性值指向的是同一块内存。因此修改新对象或者原对象,都会互相干扰。 深拷贝是将一个Object对象的内容完全拷贝一份给新对象。修改原对象的属性或者属性值,都不会影响新对象。原对象和新对象是完全独立的,互不影响。 他们具体又是如何应用的呢?我们来举几个例子说明。
一、浅拷贝 比如说,我们现在有一个对象A,他里面有两个属性id和name,还有一个空对象B,我们应该如何操作将A对象的属性拷贝给B对象呢?
var A = { name:'xl', id: 6 }; var B = {};
首先,我们可以通过一个for...in循环来遍历对象A,然后将得到的每一项赋给对象B。然后通过打印对象B查看是否将A的属性值拷贝成功。
for (k in A) {//k是属性名,A[k]是属性值 B[k] = A[k]; } console.log(B);
打印结果为:
发现B的确拷贝了A的所有属性。
按照上例,我们现在在给A对象添加一个方法,看看拷贝的结果吧!
var A = { name:'xl', id: 6, study: { doing: '学习' } };
打印结果为:
似乎这样也把我们新添的方法拷贝成功了,但是如果我们修改B对象中study的值,A对象中的值会不会变化呢?
B.study.doing = '上课'; console.log(A);
打印结果为:
可知,A里面的属性也相应被改变了。这是因为,我们浅拷贝拷贝的该方法的是更深层次对象的地址。
说明:浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用。
我们还可以通过ES6新增的语法Object.assign(target, ...sources)来实现我们的浅拷贝。
我们将上述例子通过该方法实现看看。
var A = { name:'xl', id: 6, study: { doing: '学习' } }; var B = {}; Object.assign(B,A); console.log(B);
打印结果为:
可以看出,我们的这种语法也可以实现效果,但是需要注意的是,该方法也只能实现浅拷贝。
二、深拷贝 对于深拷贝,我们的实现思路是:再对对象里面的属性和属性名通过循环表里进行拷贝。这里就要用到递归思想。 还是上面那个例子: 首先,我们封装一个函数,并将被拷贝的对象和要拷贝的对象传入,封装完成后,再通过for..in循环进行遍历。接下来具体操作为: 1、通过oldA[k]获取属性值 2、通过instanceof()判断该值的属性 3、如果值的类型是数组或者对象,则通过递归调用在此循环遍历数组或者对象里面的值进行拷贝。 4、如果值的类型是简单数据类型,就直接赋值。 代码如下:
function deepCopy(newA,oldA){ for(k in oldA){ var item = oldA[k]; if(item instanceof Array){ newA[k] = []; deepCopy(newA[k],item) }else if(item instanceof Object){ newA[k] = {}; deepCopy(newA[k],item) }else{ newA[k] = item; } } } deepCopy(B,A); console.log(B);
最后打印的结果为:
成功拷贝。
那么如果我们改变B对象的study方法里面的值会不会影响A呢?
B.study.doing = '上课'; console.log(A);
打印结果为:
可以发现,B对象里面的值发生变化并不会影响到A对象。因为:深拷贝是将一个Object对象的内容完全拷贝一份给新对象。
相信大家通过前端培训学习现在应该已经了解了深拷贝和浅拷贝。那么,他们二者的区别是什么呢?
浅拷贝和深拷贝的区别 浅拷贝是拷贝了对象的引用,当原对象发生变化的时候,拷贝对象也跟着变化;深拷贝是另外申请了一块内存,内容和原对象一样,更改原对象,拷贝对象不会发生变化