JavaScript的浅拷贝深拷贝一直都是很常见的基础问题,一般相关的问题可以直接用jQuery、lodash这样的库一行解决,但是学会了用还是要懂它背后的基础原理。
特别用这一篇笔记整理一下JavaScript浅拷贝、深拷贝的知识。
什么是浅拷贝、深拷贝
浅拷贝、深拷贝是在数组和对象下才存在的概念。浅拷贝指只拷贝了数组或对象的引用,并没有完全拷贝整个对象为一个独立的新对象,而深拷贝则是构建一个和原有对象完全一样的新对象,且它相对于新对象是独立的。
下面来举个实际的例子。
1 | var obj = { |
如果是浅拷贝,那么代码可能会类似于这样:
1 | function simpleCopy(obj) { |
我们实际用这个代码在V8下对上面定义的obj进行一个浅拷贝,并且对拷贝后得到的对象进行修改:
1 | var obj_2 = simpleCopy(obj); |
这个时候我们得到的结果是obj的a.d被也被更改成了99,所以这里浅拷贝拷贝到的实际上是引用,obj_2和obj并不是独立的。
但是对于表层的数据,浅拷贝拷贝出来的并非是引用,比如接着执行下面的代码:
1 | obj_2.b = 99; |
obj.b是不会发生变化的,因为我们的代码是把obj.b的值赋给了obj_2.b,对于number这个类型,obj_2.b得到的是真实值,但是对于object(object包括数组),obj_2这边的得到就是一个引用,我们对引用内的对象做修改自然会同时修改到源对象。
如果要做深拷贝的话,我们在拷贝的方法里不能简单用“=”赋值。
深拷贝的方法
要实现深拷贝,最简单的方式是递归:
1 | function deepCopy(obj) { |
这是一个相当简单的深拷贝,我们用这个方法来重新创造一个obj_2:
1 | var obj_2 = deepCopy(obj); |
在深拷贝下,原先的obj就没有发生变化。这里的深拷贝是一个非常简单的深拷贝,更加好的深拷贝需要考虑到环引用、继承/原型链、symbol等很多问题,具体可参考lodash的实现。