-
566 评估不是邪恶的。 糟糕地使用eval是。如果你担心它的副作用,你就错了。 你担心的副作用就是使用它的原因。顺便问一下,有人真正回答了你的问题吗? – 特格拉·德特拉 评论 2012年3月22日14:08 -
15 克隆对象是一项棘手的工作,特别是对于任意集合的自定义对象。 这可能就是为什么没有现成的方法来做这件事的原因。 – b01号机组 评论 2013年3月11日22时25分 -
12 评估() 通常是个坏主意,因为 许多Javascript引擎的优化程序在处理通过设置的变量时必须关闭 评估 。只是 评估() 在代码中可能会导致性能下降。 – user56恢复monica8 评论 2014年9月8日13:37 -
12 请注意 JSON格式 方法将丢失在JSON中没有等效项的任何Javascript类型。 例如: JSON.parse(JSON.stringify({a:null,b:NaN,c:Infinity,d:undefined,e:function(){},f:Number,g:false})) 将生成 {a:空,b:空,c:空,g:假} – 奥里亚姆人 评论 2017年5月24日13:06 -
反应社区引入了 免疫辅助因子 – Navid公司 评论 2019年7月6日7:07
67个答案
本机深度克隆
structuredClone(值)
从“@ungap/structured-clone”导入structuredClone;
结构化克隆算法不能复制功能对象; 试图引发DataCloneError异常。 克隆DOM节点同样会引发DataCloneError异常。 某些对象属性不会保留: RegExp对象的lastIndex属性未保留。 属性描述符、setter、getter和类似元数据的特性不会重复。 例如,如果一个对象用属性描述符标记为只读,那么它将在副本中读/写,因为这是默认值。 原型链没有行走或复制。
更早的答案
快速克隆并丢失数据-JSON.parse/stringify
常数a={ string:'字符串', 编号:123, bool:错误, nul:空, 日期:新日期(),//字符串化 undef:未定义,//丢失 inf:无限,//强制为“null” 回复:/.*/,//丢失 } 控制台.log(a); console.log(日期类型);// Date对象 const clone=JSON.parse(JSON.stringify(a)); console.log(克隆); console.log(clone.date类型);// .toISOString()的结果
使用库进行可靠的克隆
洛达什- 克隆深度 ; 可以通过单独导入 lodash.clonedep公司 如果您还没有使用提供深度克隆功能的库,那么它可能是您的最佳选择 兰达- 克隆 安格拉尔JS- 角度复制 jQuery(jQuery)- 扩展(true,{},oldObject) ; .clone() 仅克隆DOM元素 只是图书馆- 只是克隆 ; 零依赖npm模块库的一部分,只做一件事。 适用于各种场合的无过错实用程序。
-
138 当心! 变量A={b:[{A:[1,2,3],b:[4,5,6],c:[7,8,9]}]}; B=对象赋值({},A); 删除B.B[0].B; 它还将修改对象A! 评论 2020年9月30日12:54 -
18 @Gabriel Hautclocq这是因为 A.b公司 或 英国银行 都指向内存中的同一对象。 如果 A类 如果属性具有非对象值(如数字或字符串),则会正常复制。 但当复制包含对象值的属性时,它是按引用而不是按值复制的。 此外,请记住数组是JS中的对象。 证明: typeof[]==“object”&&[]数组实例 – 独角兽 评论 2020年12月15日13:21 -
48 @Unicornist是的,这就是为什么Object.assign没有回答这个问题:“在JavaScript中深度克隆对象的最有效方法是什么?”。 因此,至少它不应该作为ES6解决方案来进行深度克隆。 “ES6”的标题具有误导性,至少应该加以更改,以反映这不是一种深度克隆方法。 “肤浅”这个词很容易被忽视,很多人只是采用他们在Stack Overflow中找到的最简单的解决方案,而没有阅读所有内容。 依赖Object.assign进行对象克隆是危险的。 所以我说。 评论 2020年12月15日13:58 -
7 -
三
JSON.parse(JSON.stringify(obj))
var克隆对象={ knownP:obj.knownP, .. }
赋值对象({},obj);
-
14 请注意,你的替补席上有两个错误:首先,它比较了一些浅层克隆(lodash _.clone(克隆) 和 对象分配 )进行深度克隆( JSON.parse(JSON.stringify()) ). 第二,它说lodash是“深克隆”,但实际上是浅克隆。 – 乳头状物 评论 2021年2月15日14:22 -
-
请注意,reObject.assign({},obj})-这是一个浅层副本,而不是深层克隆。这意味着如果属性本身是一个对象,那么您只能获得一个引用。 – 克里斯·G 评论 2022年12月3日15:40 -
+1000用于内联克隆。 我为我的对象硬编码了一个已知属性的列表,并对其进行循环,这使我每秒可以复制3000个。 一旦我摆脱了循环,写出了对象文字中的每个属性,每毫秒大约有200万个副本。 绝对是疯狂的速度提升,我从来没有意识到环路会这么慢。 – 艾萨克·金 评论 2023年4月30日20:37
结构化克隆
const clone=structuredClone(原始);
Synchronous Node.js解决方案:非常好! 😀
const v8=要求(“v8”); const structuredClone=obj=>{ 返回v8.deserialize(v8.serialize(obj)); };
异步浏览器解决方法:可用。 😕
类StructuredCloner{ 构造函数(){ this.pendingClones _=新映射(); this.nextKey_=0; const通道=新消息通道(); this.inPort=通道端口1; this.outPort _=通道端口2; this.outPort_.onmessage=({data:{key,value}})=>{ const resol=this.pendingClones_.get(键); 解析(值); this.pendingClones_.delete(密钥); }; this.outPort_.start(); } 克隆异步(值){ return new Promise(解决=>{ const键=this.nextKey_++; this.pendingClones_.set(key,resolve); this.inPort_.postMessage({key,value}); }); } } const structuredCloneAsync=窗口结构化克隆异步= StructuredCloner.prototype.cloneAsync.bind(新Structured Cloner);
使用示例:
constmain=async()=>{ const-original={date:new-date(),number:Math.random()}; original.self=原始; const clone=等待structuredCloneAsync(原始); //它们是不同的对象: console.assert(原始!==克隆); console.assert(original.date!==clone.date); //它们是周期性的: console.assert(original.self===原始); console.assert(clone.self===克隆); //它们包含等效值: console.assert(original.number===clone.number); console.assert(数字(original.date)===数字(clone.date,克隆日期)); console.log(“断言完成”); }; main();
同步浏览器解决方案:太棒了! 🤢
const structuredClone=obj=>{ const oldState=历史记录状态; history.replaceState(obj,null); const clonedObj=历史记录状态; history.replaceState(oldState,null); return clonedObj; };
使用示例:
'使用严格'; 常量main=()=>{ const-original={date:new-date(),number:Math.random()}; original.self=原始; const clone=structuredClone(原始); //它们是不同的对象: console.assert(原始!==克隆); console.assert(original.date!==clone.date); //它们是周期性的: console.assert(original.self===原始); console.assert(clone.self===克隆); //它们包含等效值: console.assert(original.number===clone.number); console.assert(数字(original.date)===数字(clone.date,克隆日期)); console.log(“断言完成”); }; const structuredClone=obj=>{ const oldState=历史记录状态; history.replaceState(obj,null); const clonedObj=历史记录状态; history.replaceState(oldState,null); return clonedObj; }; main();
const structuredClone=obj=>{ const n=新通知(“”,{data:obj,silent:true}); n.onshow=n.close.bind(n); 返回n.data; };
使用示例:
'使用严格'; 常量main=()=>{ const-original={date:new-date(),number:Math.random()}; original.self=原始; const clone=structuredClone(原始); //它们是不同的对象: console.assert(原始!==克隆); console.assert(original.date!==clone.date); //它们是周期性的: console.assert(original.self===原始); console.assert(clone.self===克隆); //它们包含等效值: console.assert(original.number===clone.number); console.assert(数字(original.date)===数字(clone.date,克隆日期)); console.log(“断言完成”); }; const structuredClone=obj=>{ const n=新通知(“”,{data:obj,silent:true}); n.关闭(); 返回n.data; }; main();
-
59 -
332 -
1 -
5 2022年4月更新: 结构化克隆 在FF94+、Chrome 98+、Safari 15.4+和Edge 98+中可用,因此在所有当前版本的主要浏览器中都可用! – 欧纳牌手表 评论 2022年4月10日15:17 -
三 只要HTML创作委员会根本无法设计出高质量的API,并继续大量生产出被设计破坏的API,上述滥用API的行为就会继续存在(@Jeremy勇敢地尝试展示解决方案并没有冒犯)。 例如,结构化克隆算法定义了一个严格的过程(比如说,很难通过脚本进行扩展),同时将太多内容留给用户代理。 例如,Firefox无法克隆 错误 例如,对象--但MDN自豪地声明它支持 结构化克隆 朋友们,尽管这是一种解释。 – 阿蒙·迈克利 评论 2022年5月4日12:57
var newObject=JSON.parse(JSON.stringify(oldObject));
功能克隆(obj){ if(obj===null||typeof(obj)!==' obj中的对象“||”isActiveClone) 返回对象; if(obj实例日期) var temp=新对象构造函数()// 或新日期(obj); 其他的 var temp=对象构造函数(); for(obj中的var键){ if(Object.prototype.hasOwnProperty.call(obj,key)){ obj['isActiveClone']=空; temp[key]=克隆(obj[key]); 删除对象['isActiveClone']; } } 返回温度; }
-
6 -
它似乎跟踪循环引用。 例如。: 常数a={}; a['selfref']=a; a['text']='something'; 警报(a.selfref.text); 如果你试图克隆以上内容 一 不带 isActiveClone 部分,您将以无限递归结束(因为递归 克隆() 财产征用 自我参照 ). – 佩蒂29 评论 2023年3月13日11:29 -
在一行代码中克隆(而不是深度克隆)对象的有效方法
var clone=Object.assign({},obj);
assign()方法用于将所有可枚举自身属性的值从一个或多个源对象复制到目标对象。
if(!Object.assign){ Object.defineProperty(Object,'assign'{ 可枚举:false, 可配置:true, 可写:true, 值:函数(目标){ '使用严格'; if(目标===未定义||目标===null){ throw new TypeError(“无法将第一个参数转换为对象”); } var to=对象(目标); for(var i=1;i<参数长度;i++){ var nextSource=参数[i]; if(nextSource===未定义||nextSource===空){ 继续; } nextSource=对象(nextSource); var keysArray=Object.keys(nextSource); for(var nextIndex=0,len=keysArray.length;nextIndex<len;next Index++){ var nextKey=keysArray[nextIndex]; var desc=Object.getOwnPropertyDescriptor(nextSource,nextKey); if(desc!==未定义&&desc.enumerable){ to[nextKey]=nextSource[nexdKey]; } } } 返回; } }); }
-
105 -
7 尽管我测试了一些方法,但这种方法还是有效的,_.extend({},(obj))是最快的:例如,比JSON.parse快20倍,比Object.assign快60%。 它可以很好地复制所有子对象。 – 尼科 评论 2016年5月9日19:57 -
18 -
4 -
扩散算子 ... (仅限基元数组) 切片() (仅限基元数组) 拼接(0) (仅限基元数组) concat() (仅限基元数组) JSON.parse(JSON.stringify()) (仅限基本数组和文字数组) 自定义函数,如下所示(任意数组) 洛达什的 _.cloneDeep() (任意数组) jQuery的 $.extend() (任意数组) 下划线 _.clone() (仅限基本数组和文字数组)
基元=字符串、数字和布尔值 literals=对象文字 {} ,数组文字 [] any=原语、文字和原型
设arr1a=[1,'a',true];
设arr1b=[…arr1a];
设arr1d=arr1a.slice(); 设arr1c=arr1a.拼接(0); 设arr1e=arr1a.concat();
设arr2a=[1,'a',true,{},[]]; 让arr2b=JSON.parse(JSON.stringify(arr2a));
设arr3a=[1,'a',true,{},[],new Object()];
函数副本(aObject){ //防止未定义的对象 //if(!aObject)返回aObject; 让bObject=Array.isArray(aObject)? [] : {}; 出租价值; for(对象中的常量键){ //防止自我引用父对象 //如果(Object.is(aObject[key],aObject))继续; value=对象[key]; bObject[key]=(值类型===“对象”)? copy(value):值; } return bObject; } 设arr3b=副本(arr3a);
设arr3c=$.extend(true,[],arr3a);// jQuery(jQuery) 设arr3d=_.cloneDeep(arr3a);// 洛达什
-
2 -
三 在深度复制中,您不想同时复制继承的属性吗? 另外,请注意调用 拥有自己的财产 方法,为每个键创建性能命中(将函数调用推上堆栈和推下堆栈,并执行方法代码)。 评论 2021年6月30日17:47 -
1 -
1 -
@美国。 Serpooshan-同意,答案已根据以下基准进行更新( measurehat.net/Bechmarks/Show/17502/0/deep-copy-comparison公司 ) 评论 2023年4月4日23:01
函数cloneObject(obj){ var克隆={}; for(obj中的var i){ if(typeof(obj[i])==“object”&&对象[i]!= null) clone[i]=克隆对象(obj[i]); 其他的 克隆[i]=对象[i]; } 返回克隆; }
-
尝试:vara={b:1,c:3,d:{a:10,g:20,h:{today:newDate()}}}; 不为我工作。但是 对象.assign({},a) 做。 评论 2021年4月8日19:58 -
-
-
-
我已经为复杂对象扩展了此函数,但现在它不支持Date stackblitz.com/edit/typescript-vudfgn? 文件=索引.ts – 莫哈纳·拉杰什 评论 2023年2月3日16:11
//使用成员从“到”扩展“from”对象。 如果“to”为空,则返回“from”的深度克隆 函数扩展(从,到) { if(from==null||typeoffrom!=“object”)返回自; if(from.constructor!=对象&&from.constructor!=数组)从返回; if(from.constructor==日期|| from.confructor==RegExp|| from constructor==函数|| from.constructor==字符串||from.confructor==Number ||from constructor==布尔值) 从.constructor(from)返回new; to=to | | new from.constructor(); for(from中的var名称) { to[name]=typeof to[name]==“undefined”? 扩展(从[name],null):到[name]; } 返回; }
var对象= { date:new date(), func:函数(q){return 1+q;}, 编号:123, text:“asdasd”, 数组:[1,“asd”], regex:新RegExp(/aaa/i), 子bj: { 编号:234, 文本:“asdsaD” } } var克隆=扩展(obj);
变量对象={ a: 1、, b: { c: 2个 } } var newObj=JSON.parse(JSON.stringify(obj)); 对象b.c=20; 控制台.log(obj);// {a:1,b:{c:20}} console.log(newObj);// {a:1,b:{c:2}}
函数cloneObject(obj){ var克隆={}; for(obj中的var i){ if(obj[i]!=空&&typeof(obj[2])==“对象”) clone[i]=克隆对象(obj[i]); 其他的 克隆[i]=对象[i]; } 返回克隆; } 变量对象={ a: 1、, b: { c: 2个 } } var newObj=克隆对象(obj); 对象b.c=20; 控制台.log(obj);// {a:1,b:{c:20}} console.log(newObj);// {a:1,b:{c:2}}
变量对象={ a: 1、, b: { c: 2个 } } var newObj=_.cloneDeep(obj); 对象b.c=20; 控制台.log(obj);// {a:1,b:{c:20}} console.log(newObj);// {a:1,b:{c:2}}
变量对象={ a: 1、, b: 2个 } var newObj=_.clone(obj); 对象b=20; 控制台.log(obj);// {a:1,b:20} console.log(newObj);// {a:1,b:2}
变量对象={ a: 1、, b: { c: 2个 } } var newObj=对象分配({},obj); 对象b.c=20; 控制台.log(obj);// {a:1,b:{c:20}} console.log(newObj);// {a:1,b:{c:20}-->错误 //注意:无法复制原型链上的属性和非枚举属性。
变量对象={ a: 1、, b: 2个 } var newObj=_.clone(obj); 对象b=20; 控制台.log(obj);// {a:1,b:20} console.log(newObj);// {a:1,b:2}
变量对象={ a: 1、, b: { c: 2个 } } var newObj=_.cloneDeep(obj); 对象b.c=20; 控制台.log(obj);// {a:1,b:{c:20}} console.log(newObj);// {a:1,b:{c:20}-->错误 //(为提供的普通对象创建一个浅层复制的克隆。任何嵌套的对象或数组都将通过引用复制,而不是复制。)
变量obj={a:1,b:2,c:3,d:4};
ES5+,使用简单的功能为您复制: 函数deepCopyObj(obj){ if(null==obj||“object”!=typeof obj)返回obj; if(obj实例日期){ var copy=新日期(); copy.setTime(obj.getTime()); 返回副本; } if(obj实例数组){ var副本=[]; 对于(var i=0,len=obj.length;i<len;i++){ copy[i]=deepCopyObj(obj[i]); } 返回副本; } if(obj对象实例){ var-copy={}; for(obj中的var属性){ 如果(obj.hasOwnProperty(attr))copy[attr]=deepCopyObj(obj[attr]); } 返回副本; } throw new Error(“无法复制对象this object.”); } ES5+,使用 JSON.parse格式 和 JSON.stringify格式 . var deepCopyObj=JSON.parse(JSON.stringify(obj)); 角度: var deepCopyObj=角度复制(obj); jQuery: var deepCopyObj=jQuery.extend(true,{},obj); Underscore.js和Lodash: var deepCopyObj=_.cloneDeep(obj)// Underscore.js的最新版本进行了浅层复制
var克隆=函数(){ var newObj=(数组的此实例)? [] : {}; for(此处为var i){ if(此[i]&&此[i]的类型==“对象”){ newObj[i]=此[i].clone(); } 其他的 { newObj[i]=这个[i]; } } return newObj; }; Object.defineProperty(Object.protype,“clone”,{value:clone,enumerable:false});
npm安装克隆
ender构建克隆[…]
var clone=require(“克隆”); vara={foo:{bar:'baz'}};// a的初始值 var b=克隆(a);// 克隆a->b a.foo.bar='foo';// 更改a 控制台.log(a);// {foo:{bar:'foo'}} console.log(b);// {foo:{bar:'baz'}}
//如果Object.create尚未定义,我们只需进行简单的填充, //没有第二个论点,因为这就是我们这里所需要的 var object_create=对象创建; if(typeof object_create!==“函数”){ object_create=函数(o){ 函数F(){} F.原型=o; 返回新的F(); }; } 函数deepCopy(obj){ if(obj==null||typeof(obj)!==' 对象'){ 返回对象; } //确保返回的对象与原始对象具有相同的原型 var ret=对象创建(obj.constructor.prototype); for(obj中的var键){ ret[key]=深度复制(obj[key]); } 返回ret; }
/** *深度复制对象(复制其所有对象属性、子属性等) *的改进版本 http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone *如果构造函数具有必需的参数,则不会中断 * *它还借用了一些代码 http://stackoverflow.com/a/11621004/560114 */ 函数deepCopy(src,/*内部*/_visited,_copiesVisited){ if(src===null||typeof(src)!==' 对象'){ 返回src; } //尊重本机/自定义克隆方法 if(src.clone的类型==“函数”){ return src.clone(true); } //特殊情况: //日期 if(src-instanceof Date){ return new Date(src.getTime()); } //注册Exp if(RegExp的src实例){ return new RegExp(src); } //DOM元素 if(src.nodeType&&typeof src.cloneNode==“函数”){ return src.cloneNode(true); } //如果需要,初始化访问的对象数组。 //这用于检测循环引用。 if(已访问===未定义){ _已访问=[]; _访问的副本=[]; } //检查此对象是否已被访问 var i,len=访问长度; 对于(i=0;i<len;i++){ //如果是这样的话,把我们已经制作好的副本拿来 if(src===访问[i]){ return _copiesVisited[i]; } } //阵列 if(Object.prototype.toString.call(src)==“[Object Array]”){ //[].slice()本身将进行软克隆 var ret=src.slice(); //将其添加到访问过的数组 _visited.push(src); _copiesVisited.push(ret); var i=重试长度; 同时(i--){ ret[i]=深度复制(ret[i],_visited,_copiesVisited); } 返回ret; } //如果我们到达这里,我们有一个常规对象 //确保返回的对象与原始对象具有相同的原型 var proto=(Object.getPrototypeOf?Object.getProtoypeOv(src):src__ 质子__); if(!原型){ proto=src.constructor.protype// 这一行可能只有非常旧的浏览器才能访问 } var dest=对象创建(原型); //将此对象添加到访问过的数组 _visited.push(src); _copiesVisited.push(dest); for(src中的var键){ //注意:这不会保留ES5属性属性,如“可写”、“可枚举”等。 //有关如何对此进行修改的示例,请参见singleMixin()函数 dest[key]=deepCopy(src[key],_visited,_copiesVisited); } 返回目的地; } //如果Object.create尚未定义,我们只需进行简单的填充, //没有第二个论点,因为这就是我们这里所需要的 var object_create=对象创建; if(typeof object_create!==“函数”){ object_create=函数(o){ 函数F(){} F.原型=o; 返回新的F(); }; }
var objToCreate=JSON.parse(JSON.stringify(cloneThis));
函数对象(o){ 函数F(){} F.原型=o; 返回新的F(); } var newObject=对象(oldObject);
var newObject=Object.create(oldObject);
newObject.a;// 是5
oldObject.hasOwnProperty(a);// 是真的 newObject.hasOwnProperty(a);// 是false
var对象=[{'a':1},{'b':2}]; var deep=_.cloneDeep(对象); console.log(深度[0]===对象[0]); //=>假
varorigin={foo:{}}; var copy=Object.keys(origin).reduce(函数(c,k){c[k]=origin[k];返回c;},{}); console.log(源,副本); console.log(origin==副本);// 假 console.log(origin.foo==副本.foo);// 真的
varorigin={foo:{}}; var-copy=Object.assign({},原点); console.log(源,副本); console.log(origin==副本);// 假 console.log(origin.foo==副本.foo);// 真的
函数jQueryClone(obj){ return jQuery.extend(true,{},obj) } 函数JSONClone(obj){ return JSON.parse(JSON.stringify(obj)) } var arrayLikeObj=[[1,“a”,“b”],[2,“b“,”a“]]; arrayLikeObj.names=[“m”,“n”,“o”]; var JSONCopy=JSONClone(arrayLikeObj); var jQueryCopy=jQueryClone(arrayLikeObj); alert(“arrayLikeObj是数组实例吗?”+(arraySikeObj-instanceof array)+ “\njQueryClone是数组实例吗?”+(jQueryCopy instanceof array)+ “arrayLikeObj名称是什么?”+arrayLike Obj.names+ “\n JSONClone名称是什么?”+JSONCopy.names)
var clone=JSON.parse(JSON.stringify(obj));
函数cloneObject(obj){ if(obj===null||typeof(obj)!==' 对象') 返回对象; var temp=对象构造函数();// 改变 for(obj中的var键){ if(Object.prototype.hasOwnProperty.call(obj,key)){ obj['isActiveClone']=空; temp[key]=克隆对象(obj[key]); 删除对象['isActiveClone']; } } 返回温度; } var b=克隆对象({“a”:1,“b”:2});// 打电话
变量a={“a”:1,“b”:2}; var b=JSON.parse(JSON.stringfy(a));
变量a={“a”:1,“b”:2}; //深度复制 var newObject=jQuery.extend(true,{},a);
复制时不会触发getter/setter。 保留getter/setter。 保留原型信息。 适用于两者 对象-边 和 功能性的 面向对象 写作风格。
功能克隆(目标、源){ for(让键入源代码){ //使用getOwnPropertyDescriptor而不是source[key]来防止触发setter/getter。 let描述符=Object.getOwnPropertyDescriptor(源,键); if(字符串的描述符.value实例){ target[key]=新字符串(descriptor.value); } else if(数组的描述符.value实例){ target[key]=克隆([],descriptor.value); } else if(对象的描述符.value实例){ let prototype=Reflect.getPrototypeOf(descriptor.value); 让cloneObject=克隆({},descriptor.value); Reflect.setPrototypeOf(cloneObject,prototype); target[key]=克隆对象; } 其他{ Object.defineProperty(目标、键、描述符); } } let prototype=Reflect.getPrototypeOf(源); Reflect.setPrototypeOf(目标,原型); 返回目标; }
功能克隆(obj,克隆){ //制作“obj”的深度副本。 处理循环结构 //在“clones”参数中跟踪克隆的obj。 功能 //包括但不克隆。 函数成员被克隆。 var new_obj, 已经克隆, t=对象类型, i=0, 我, 一对; clones=克隆||[]; if(obj===空){ 返回对象; } if(t===“对象”||t==“函数”){ //看看我们是否已经克隆了obj 对于(i=0,l=克隆长度;i<l;i++){ pair=克隆[i]; if(对[0]===obj){ already_clone=对[1]; 断裂; } } if(已克隆){ return already_clone; }其他{ if(t===“对象”){//创建新对象 new_obj=新对象构造函数(); }else{//按原样使用函数 new_obj=对象; } clones.push([obj,new_obj]);// 跟踪我们克隆的对象 for(obj中的键){//克隆对象成员 if(obj.hasOwnProperty(key)){ new_obj[key]=克隆(obj[key],克隆); } } } } return new_obj | obj; }
a=[] a.推动(“b”、“c”、a) aa=克隆(a) aa===a//=>假 aa[2]===a//=>假 aa[2]===a[2]//=>假 aa[2]===aa//=>真
f=新功能 f.a=a ff=克隆(f) ff===f//=>真 ff.a===a//=>假
功能克隆(obj){ var regExp=/^\d {4}- \d日 {2}- \d日 {2} T型 \d{2}:\d{2{:\d{2}\。 \d日 {3} Z轴 $/; return JSON.parse(JSON.stringify(obj),函数(k,v){ if(v===字符串类型&®Exp.test(v)) return新日期(v) 返回v; }) } //用法: var原始={ a: [1,null,未定义,0,{a:null},new Date()], b:{ c(){返回0} } } var cloned=克隆(原始) console.log(克隆)
杰斯佩夫 在这里排名第一: https://jsperf.com/deep-copy-vs-json-stringify-json-parse/5 杰斯本 从上述答案中可以看出,递归深度克隆击败了所有其他提到的克隆: http://jsben.ch/13YKQ网站
函数cloneDeep(o){ 让newO 让我来吧 if(typeof o!==“object”)返回o 如果(!o)返回o if(Object.prototype.toString.apply(o)===“[Object Array]”){ 新O=[] 对于(i=0;i<o.length;i+=1){ newO[i]=克隆深度(o[i]) } 返回newO } 新O={} for(i in o){ 如果(o.hasOwnProperty(i)){ newO[i]=克隆深度(o[i]) } } 返回newO }
-
2 我喜欢这种方法,但它不能正确处理日期; 考虑添加以下内容 if(o instanceof Date)返回新的Date(o.valueOf()); 检查null后` – 路易斯 评论 2017年8月21日22:53 -
-
//obj目标对象,vals源对象 var setVals=函数(obj,vals){ if(对象和值){ for(vals中的var x){ if(vals.hasOwnProperty(x)){ if(obj[x]&&vals[x]==“对象”类型){ obj[x]=设置值(obj[x],vals[x]); }其他{ obj[x]=值[x]; } } } } 返回对象; };