日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深度克隆与浅度克隆

發(fā)布時(shí)間:2024/1/1 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深度克隆与浅度克隆 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

javascript中對象的深度克隆

深度克隆:原不變

淺克隆:通過“=”賦值操作;基礎(chǔ)類型:值傳遞;對象:引用。

以下number function string 執(zhí)行的淺克隆(賦值操作),但是結(jié)果表現(xiàn)形式與深度克隆一致,都是原不變,相當(dāng)于深克隆。 淺==深

對于基礎(chǔ)類型可以理解賦值操作原來的不變,但是function作為引用,原也不變,是因?yàn)?#xff0c;函數(shù)的克隆會在內(nèi)存單獨(dú)開辟空間,互不影響,表面是淺克隆,實(shí)際是深克隆。

大家能看到,我們直接通過普通賦值的方式,就實(shí)現(xiàn)了函數(shù)的克隆,并且不會影響之前的對象。原因就是函數(shù)的克隆會在內(nèi)存單獨(dú)開辟一塊空間,互不影響。

但是Object、 Array 通過“=”賦值操作,原變了。這是淺克隆。


js中的數(shù)據(jù)類型分為兩大類:原始類型和對象類型。(1)原始類型包括:數(shù)值、字符串、布爾值、null、undefined(后兩個(gè)是特殊的原始值,這里不做詳細(xì)的說明,我的上一篇博客有談到過一些)(2)對象類型包括:對象即是屬性的集合,當(dāng)然這里又兩個(gè)特殊的對象----函數(shù)(js中的一等對象)、數(shù)組(鍵值的有序集合)。 好了既然對象分為這兩類,這兩種類型在復(fù)制克隆的時(shí)候是有很大區(qū)別的。原始類型存儲的是對象的實(shí)際數(shù)據(jù),而對象類型存儲的是對象的引用地址(對象的實(shí)際內(nèi)容單獨(dú)存放,為了減少數(shù)據(jù)開銷通常存放在內(nèi)存中)。ps:說到這里,大家要知道,對象的原型也是引用對象,它把原型的方法和屬性放在內(nèi)存當(dāng)中,通過原型鏈的方式來指向這個(gè)內(nèi)存地址。 二、克隆的概念 淺度克隆:原始類型為值傳遞,對象類型仍為引用傳遞。 深度克隆:所有元素或?qū)傩跃耆珡?fù)制,與原對象完全脫離,也就是說所有對于新對象的修改都不會反映到原對象中。 三、淺克隆的表現(xiàn) 1,原始類型 看下面一段代碼: 復(fù)制代碼 //數(shù)值克隆的表現(xiàn) var a="1"; var b=a; b="2"; console.log(a);// "1" console.log(b);// "2" //字符串克隆的表現(xiàn) var c="1"; var d=c; d="2"; console.log(c);// "1" console.log(d);// "2" //字符串克隆的表現(xiàn) var x=true; var y=x; y=false; console.log(x);// true console.log(y);// false 復(fù)制代碼 從上面的代碼大家可以看出,原始類型即使我們采用普通的克隆方式仍能得到正確的結(jié)果,原因就是原始類型存儲的是對象的實(shí)際數(shù)據(jù)。 2.對象類型 前面說過,函數(shù)式一等對象,當(dāng)然也是對象類型,但是函數(shù)的克隆通過淺克隆即可實(shí)現(xiàn) 復(fù)制代碼 var m=function(){alert(1);}; var n=m; n=function(){alert(2);}; console.log(m());//1 console.log(n());//2 復(fù)制代碼 大家能看到,我們直接通過普通賦值的方式,就實(shí)現(xiàn)了函數(shù)的克隆,并且不會影響之前的對象。原因就是函數(shù)的克隆會在內(nèi)存單獨(dú)開辟一塊空間,互不影響。 好了,說了這個(gè)特殊的”關(guān)系戶“以后,我們來說說普通的”選手“。為了方便后續(xù)的代碼表現(xiàn),我這里定義一個(gè)復(fù)雜的對象類型oPerson。下面看一下對象類型的淺復(fù)制有什么危害: 復(fù)制代碼 var oPerson={ oName:"rookiebob", oAge:"18", oAddress:{ province:"beijing" }, ? ? ofavorite:[ "swimming", {reading:"history book"} ], skill:function(){ console.log("bob is coding"); } }; function clone(obj){ var result={}; for(key in obj){ result[key]=obj[key]; } return result; } var oNew=clone(oPerson); console.log(oPerson.oAddress.province);//beijing oNew.oAddress.province="shanghai"; console.log(oPerson.oAddress.province);//shanghai 復(fù)制代碼 通過上面的代碼,大家能看到,經(jīng)過對象克隆以后,我修改oNew的地址,發(fā)現(xiàn)原對象oPerson也被修改了。這說明對象的克隆不夠徹底,那也就是說深度克隆失敗! 四、深克隆的實(shí)現(xiàn) 為了保證對象的所有屬性都被復(fù)制到,我們必須知道如果for循環(huán)以后,得到的元素仍是Object或者Array,那么需要再次循環(huán),直到元素是原始類型或者函數(shù)為止。為了得到元素的類型,我們定義一個(gè)通用函數(shù),用來返回傳入對象的類型。 復(fù)制代碼 //返回傳遞給他的任意對象的類 function isClass(o){ if(o===null) return "Null"; if(o===undefined) return "Undefined"; return Object.prototype.toString.call(o).slice(8,-1); } 復(fù)制代碼 PS:Object.prototype.toString.call(o)能直接返回對象的類屬性,形如"[object class]"的字符串,我們通過截取class,并能知道傳入的對象是什么類型。 當(dāng)然這里有兩個(gè)疑問需要解釋下: (1)為什么不直接用toString方法?這是為了防止對象中的toString方法被重寫,為了正確的調(diào)用toString()版本,必須間接的調(diào)用Function.call()方法 (2)為什么不使用typeof來直接判斷類型?因?yàn)閷τ贏rray而言,使用typeof(Array)返回的是object,所以不能得到正確的Array,這里對于后續(xù)的數(shù)組克隆將產(chǎn)生致命的問題。 萬事俱備,只欠曹操了,下面就正兒八經(jīng)的開始克隆。 復(fù)制代碼 //深度克隆 function deepClone(obj){ var result,oClass=isClass(obj); //確定result的類型 if(oClass==="Object"){ result={}; }else if(oClass==="Array"){ result=[]; }else{ return obj; } for(key in obj){ var copy=obj[key]; if(isClass(copy)=="Object"){ result[key]=arguments.callee(copy);//遞歸調(diào)用 }else if(isClass(copy)=="Array"){ result[key]=arguments.callee(copy); }else{ result[key]=obj[key]; } } return result; } //返回傳遞給他的任意對象的類 function isClass(o){ if(o===null) return "Null"; if(o===undefined) return "Undefined"; return Object.prototype.toString.call(o).slice(8,-1); } var oPerson={ oName:"rookiebob", oAge:"18", oAddress:{ province:"beijing" }, ? ? ofavorite:[ "swimming", {reading:"history book"} ], skill:function(){ console.log("bob is coding"); } }; //深度克隆一個(gè)對象 var oNew=deepClone(oPerson); oNew.ofavorite[1].reading="picture"; console.log(oNew.ofavorite[1].reading);//picture console.log(oPerson.ofavorite[1].reading);//history book oNew.oAddress.province="shanghai"; console.log(oPerson.oAddress.province);//beijing console.log(oNew.oAddress.province);//shanghai 復(fù)制代碼 從上面的代碼可以看到,深度克隆的對象可以完全脫離原對象,我們對新對象的任何修改都不會反映到原對象中,這樣深度克隆就實(shí)現(xiàn)了。 這里要注意一點(diǎn)的就是:為什么deepClone這個(gè)函數(shù)中的result一定要判斷類型?這里有一種情況,如果你的result直接是{}對象,我明明傳進(jìn)去的是一個(gè)數(shù)組,結(jié)果你復(fù)制完了以后,變成了一個(gè)對象了。 復(fù)制代碼 //深度克隆 function deepClone(obj){ var result={},oClass=isClass(obj); // if(oClass==="Object"){ // ? ? result={}; // }else if(oClass==="Array"){ // ? ? result=[]; // }else{ // ? ? return obj; // } for(key in obj){ var copy=obj[key]; if(isClass(copy)=="Object"){ result[key]=arguments.callee(copy); }else if(isClass(copy)=="Array"){ result[key]=arguments.callee(copy); }else{ result[key]=obj[key]; } } return result; } function isClass(o){ if(o===null) return "Null"; if(o===undefined) return "Undefined"; return Object.prototype.toString.call(o).slice(8,-1); } //克隆一個(gè)數(shù)組 var arr=["a","b","c"]; var oNew=deepClone(arr); console.log(oNew);//Object {0: "a", 1: "b", 2: "c"}?

總結(jié)

以上是生活随笔為你收集整理的深度克隆与浅度克隆的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。