关于深浅拷贝
深拷贝和浅拷贝是很常见的操作,但从概念的角度,却很难描述清楚。
先说概念,没有一个平台或文章对深拷贝和浅拷贝的概念提出所谓的标准定义,大都是一段被大多数人认可的常规的描述。
浅拷贝:如果在拷贝这个对象的时候,只对基本数据类型进行了拷贝,而对引用数据类型只是进行了引用的传递,而没有真实的创建一个新的对象。
深拷贝:在对引用数据类型进行拷贝的时候,创建了一个新的对象,并且复制其内的成员变量。
从以上两段描述,可以得出以下几点:
深浅拷贝都是针对引用数据类型的
深浅拷贝的区别点在于对内部的引用数据类型的引用方式
深浅拷贝的返回结果是否是一个新的对象
第一点,深浅拷贝都是针对引用数据类型的。也就是说,深浅拷贝是引用数据类型才有的概念,对于基本数据类型是无所谓深浅拷贝的。所以在实现深浅拷贝的时候,只要检验当前数据是否为引用数据类型即可,如果是引用数据类型,则继续操作,反之,则直接返回即可
第二点,深浅拷贝的区别点在于对内部的引用数据类型的引用方式。浅拷贝对内部的引用数据类型使用的是同一个引用地址,深拷贝则是创建了一个新的地址,并将引用类型的数据重新拷贝了一份,然后将新的地址引向了新拷贝的数据。以上只是说了针对内部引用类型的数据的操作,而对于内部的基本类型的数据则做了相同的操作,都是新生成了一份新的数据并保存
此处有一点需要注意和说明,是关于浅拷贝和赋值,赋值不等于浅拷贝,很多人可以区别深拷贝和浅拷贝,但经常在浅拷贝和赋值之间混淆
注意第7行 const person1 = person
,此处为赋值,是直接将 person
的引用赋值给了 person1
,所以当修改 person1
的 name
值时,person
的 name
也发生了变化
同样注意 7 ~ 9 行,此处使用了 ES6
的扩展运算符,再看输出结果,person.name
的值并没有发生变化,而 person.interest
却发生了变化。此时完成的就是一次浅拷贝
赋值是对引用类型的地址进行赋值,指向的是同一个地址
浅拷贝是对引用类型数据中的引用类型的地址进行的赋值
听上去比较拗口,可以理解为,赋值完成的是对引用类型数据本身的指向,浅拷贝完成的是对引用类型数据中的子引用类型数据的指向,也可以解释为,赋值针对的是引用类型本身,浅拷贝针对的是引用类型内的引用类型,针对的层级不同
第三点,深浅拷贝的返回结果是否是一个新的对象。确切的说,深浅拷贝返回的都是一个新的引用类型数据,不同的是,深拷贝返回的结果和原数据是完全独立的,浅拷贝返回的结果和原数据在带有子引用类型的情况下是有牵连的
如何区分深浅拷贝?凡是不经过特殊处理的,肯定不是深拷贝,但经过特殊处理的,未必是深拷贝。多读几遍,你品,你细品。
何为特殊处理?反向解释就是,不能直接得到结果的处理。例如,上例中的扩展运算符,就不属于特殊处理,所以使用扩展运算符得到的是浅拷贝,再比如数组的 concat
方法,得到的是一个新数组,但对其子元素中的引用类型数据,完成的也是浅拷贝
想要完成深拷贝,必须要经过一些特殊的处理,要么手动编写函数实现,要么调用现成的工具库函数,这也是为什么经常会遇到要求手写深拷贝的试题,至少目前没有提供出直接的方法完成深拷贝
关于深拷贝的实现,网络上有很多,此处不再展开描写。本文主要针对深浅拷贝、赋值的一些理论点进行比较和描述,加深对于深浅拷贝的理解
版权声明: 本文为 InfoQ 作者【西贝】的原创文章。
原文链接:【http://xie.infoq.cn/article/e19457358b1ae9b6a0000d50b】。文章转载请联系作者。
评论