Discuz! Board

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 1|回复: 0

JavaScript 中对象的深拷贝

[复制链接]

19万

主题

0

回帖

57万

积分

超级版主

Rank: 8Rank: 8

积分
577235
发表于 前天 13:15 | 显示全部楼层 |阅读模式

如果您想订阅本博客内容,每天自动发到您的邮箱中,请点这里



在JS中,对对象进行拷贝的场景比较常见。但是简单的复制语句只能对对象进行浅拷贝,即复制的是一份引用,而不是它所引用的对象。而更多的时候,我们希望对对象进行深拷贝,避免原始对象被无意修改。



对象的深拷贝与浅拷贝的区别如下:




浅拷贝:仅仅复制对象的引用,而不是对象本身;


深拷贝:把复制的对象所引用的全部对象都复制一遍。



一 浅拷贝的实现


浅拷贝的实现方法比较简单,只要使用是简单的复制语句即可。



11 方法一:简单的复制语句

* ================ 浅拷贝 ================ *  C(O) {= {};  (O) {
[] = O[];
}  ;
}
* ================ 客户端调用 ================ *= {
: "",
: {
: "",
: 21 },
: ["B", "T", "J"],
: () {
(" ");
}
}  O = C();  对象拷贝 (O);  {: "", : 21} (O);  ["B", "T", "J"] (O);  () { (" "); }  修改拷贝后的对象 O = "";
O = [1, 2, 3];
O = () { (""); }; ();  {: "", : 21}原对象所引用的对象被修改了 ();  ["B", "T", "J"]  原对象所引用的对象未被修改 ();  () { (" "); }  原对象所引用的函数未被修改

12 方法二:O()


O()方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是O()进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。


  = { : {: "", : 21} };  O = O({}, );

O = ""; ();  ""

二 深拷贝的实现


要实现深拷贝有很多办法,有最简单的JSON()方法,也有常用的递归拷贝方法,和ES5中的O()方法。



21 方法一:使用JSON()方法


要实现深拷贝有很多办法,比如最简单的办法是使用JSON():


* ================ 深拷贝 ================ *  C(O) {= {};  {
= JSON(JSON(O));
}  ;
}
* ================ 客户端调用 ================ *= {
: {
: "",
: 21 }
}  O = C();
O = ""; ();  ""

这种方法简单易用。



但是这种方法也有不少坏处,譬如它会抛弃对象的。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成O。



这种方法能正确处理的对象只有N, S, B, A, 扁平对象,即那些能够被  直接表示的数据结构。RE对象是无法通过这种方式深拷贝。



22 方法二:递归拷贝


代码如下:


* ================ 深拷贝 ================ *  C(O, O) {= O || {};  (O) {  ( O[] === '') {
[] = (O[] === A) ? [] : {}; (O[], []);
}  {
[] = O[];
}
}  ;
}

上述代码确实可以实现深拷贝。但是当遇到两个互相引用的对象,会出现死循环的情况。



为了避免相互引用的对象导致死循环的情况,则应该在遍历的时候判断是否相互引用对象,如果是则退出循环。



改进版代码如下:


* ================ 深拷贝 ================ *  C(O, O) {= O || {};  (O) {= O[];  避免相互引用对象导致死循环,如O = O的情况 ( === ) { ;
}  (  === '') {
[] = ( === A) ? [] : {}; (, []);
}  {
[] = ;
}
}  ;
}

23 方法三:使用O()方法


直接使用 O = O(O),可以达到深拷贝的效果。


* ================ 深拷贝 ================ *  C(O, O) {= O || {};  (O) {= O[];  避免相互引用对象导致死循环,如O = O的情况 ( === ) { ;
}  (  === '') {
[] = ( === A) ? [] : O();
}  {
[] = ;
}
}  ;
}

三 参考:Q()方法的实现


Q的Q()也实现了对象的深拷贝。下面将官方代码贴出来,以供参考。



官方链接地址:。


Q = Q = () {  , , , , IA, ,
= [ 0 ] || {},
= 1,
= ,
= ;  H (=== "" ) {
= ;  S  = [  ] || {};
++;
}  H ()  (!== ""  !QF(  ) ) {
= {};
}  E Q (  ===  ) {
= ;
--;
}  ( ;; ++ ) {  O-( (  = [  ] ) !=  ) {  E() {
= [  ];
= [  ];  P -(  ===  ) { ;
}  R  '  (( QPO(  ) ||
( IA = QA(  ) ) ) ) {  ( IA ) {
IA = ;
=QA(  ) ?  : [];

}  {
=QPO(  ) ?  : {};
}  N,[  ] = Q( , ,  );  D'}(  !==  ) {
[  ] = ;
}
}
}
}  R;
};




蓝蓝设计()是一家专注而深入的界面设计,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计、界面设计、界面设计、包装设计、图标定制、用户体验、交互设计、建设、平面设计服务






我们有充分的理由相信电子病历医疗数据分析界面会成为行业的主流,会逐步影响越来越多的人。北京兰亭妙微(蓝蓝设计)是一家专注而卓越的UI界面设计公司,以良好的服务为众多优秀企业提供卓越的UI咨询、竞品分析、交互设计、UI界面设计、大数据可视化设计、嵌入式软件界面设计开发、图标icon设计、大型网站设计、用户体验设计、软件开发....是一家从用户研究、交互设计及优化咨询、软件和网站设计、界面开发实施全方位提供解决方案的创新型设计公司。http://www.lanlanwork.com

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|墨玲承奔网络公司

GMT+8, 2025-1-6 20:10 , Processed in 0.184415 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表