談到對象的克隆,一定要說一下對象的概念。javascript
js中的數據類型分爲兩大類:原始類型和對象類型。
(1)原始類型包括:數值、字符串、布爾值、null、undefined(後兩個是特殊的原始值,這裏不作詳細的說明,個人上一篇博客有談到過一些)
(2)對象類型包括:對象便是屬性的集合,固然這裏又兩個特殊的對象----函數(js中的一等對象)、數組(鍵值的有序集合)。html
好了既然對象分爲這兩類,這兩種類型在複製克隆的時候是有很大區別的。原始類型存儲的是對象的實際數據,而對象類型存儲的是對象的引用地址(對象的實際內容單獨存放,爲了減小數據開銷一般存放在內存中)。ps:說到這裏,你們要知道,對象的原型也是引用對象,它把原型的方法和屬性放在內存當中,經過原型鏈的方式來指向這個內存地址。java
淺度克隆:原始類型爲值傳遞,對象類型仍爲引用傳遞。數組
深度克隆:全部元素或屬性均徹底複製,與原對象徹底脫離,也就是說全部對於新對象的修改都不會反映到原對象中。函數
1,原始類型prototype
看下面一段代碼:
code
//數值克隆的表現 var a="1"; var b=a; b="2"; console.log(a);// "1" console.log(b);// "2"
//字符串克隆的表現 var c="1"; var d=c; d="2"; console.log(c);// "1" console.log(d);// "2"
//字符串克隆的表現 var x=true; var y=x; y=false; console.log(x);// true console.log(y);// false
從上面的代碼你們能夠看出,原始類型即便咱們採用普通的克隆方式仍能獲得正確的結果,緣由就是原始類型存儲的是對象的實際數據。
PS:對象的簡易克隆小技巧:var tmpObj = JSON.parse(JSON.stringify(傳入對象));
2.對象類型htm
前面說過,函數式一等對象,固然也是對象類型,可是函數的克隆經過淺克隆便可實現對象
var m=function(){alert(1);}; var n=m; n=function(){alert(2);}; console.log(m());//1 console.log(n());//2
你們能看到,咱們直接經過普通賦值的方式,就實現了函數的克隆,而且不會影響以前的對象。緣由就是函數的克隆會在內存單獨開闢一塊空間,互不影響。blog
好了,說了這個特殊的」關係戶「之後,咱們來講說普通的」選手「。爲了方便後續的代碼表現,我這裏定義一個複雜的對象類型oPerson。下面看一下對象類型的淺複製有什麼危害:
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
經過上面的代碼,你們能看到,通過對象克隆之後,我修改oNew的地址,發現原對象oPerson也被修改了。這說明對象的克隆不夠完全,那也就是說深度克隆失敗!
4、深克隆的實現
爲了保證對象的全部屬性都被複制到,咱們必須知道若是for循環之後,獲得的元素還是Object或者Array,那麼須要再次循環,直到元素是原始類型或者函數爲止。爲了獲得元素的類型,咱們定義一個通用函數,用來返回傳入對象的類型。
//返回傳遞給他的任意對象的類 function isClass(o){ return Object.prototype.toString.call(o).slice(8,-1); }
PS:Object.prototype.toString.call(o)能直接返回對象的類屬性,形如"[object class]"的字符串,咱們經過截取class,並能知道傳入的對象是什麼類型
固然這裏有兩個疑問須要解釋下:
(1)爲何不直接用toString方法?這是爲了防止對象中的toString方法被重寫,爲了正確的調用toString()版本,必須間接的調用Function.call()方法
(2)爲何不使用typeof來直接判斷類型?由於對於Array而言,使用typeof(Array)返回的是object,因此不能獲得正確的Array,這裏對於後續的數組克隆將產生致命的問題。
下面就是真正的深度克隆
//深度克隆 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);//遞歸調用 }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"); } }; //深度克隆一個對象 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
從上面的代碼能夠看到,深度克隆的對象能夠徹底脫離原對象,咱們對新對象的任何修改都不會反映到原對象中,這樣深度克隆就實現了。
這裏要注意一點的就是:爲何deepClone這個函數中的result必定要判斷類型?這裏有一種狀況,若是你的result直接是{}對象,我明明傳進去的是一個數組,結果你複製完了之後,變成了一個對象了。
//深度克隆 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); } //克隆一個數組 var arr=["a","b","c"]; var oNew=deepClone(arr); console.log(oNew);//Object {0: "a", 1: "b", 2: "c"}
做爲知識點記錄,轉載自:http://www.2cto.com/kf/201409/332955.html