javascript對象的深度複製

來源:互聯網
上載者:User

標籤:深複製   並且   函數   複製   console   min   add   完全   key   

在做項目的時候需要向對象裡面添加新屬性,又不想修改原對象。於是就寫: var newObj = oldObj,但是新對象屬性改變後就對象也會跟著改變,這是因為無論是新對象還是舊對象,指向的記憶體位址都是一樣的,改變了誰都改變了 記憶體中的資料。

於是找到了一個取巧的方法就是先把舊對象轉化為字串 然後 在轉化為對象給新對象,雖然可以達到效果,但是總感覺有點不正規。於是想到了深度複製

function cloneObjectFn (obj){     // 對象複製         return JSON.parse(JSON.stringify(obj))}
一、js中的對象  談到對象的複製,必定要說一下對象的概念。  js中的資料類型分為兩大類:原始類型和物件類型。  (1)原始類型包括:數值、字串、布爾值、null、undefined  (2)物件類型包括:對象即是屬性的集合,當然這裡又兩個特殊的對象----函數(js中的一等對象)、數組(索引值的有序集合)。  好了既然對象分為這兩類,這兩種類型在複製複製的時候是有很大區別的。原始類型儲存的是對象的實際資料,而物件類型儲存的是對象的引用地址(對象的實際內容單獨存放,為了減少資料開銷通常存放在記憶體中)。ps:大家要知道,對象的原型也是引用對象,它把原型的方法和屬性放在記憶體當中,通過原型鏈的方式來指向這個記憶體位址。 二、複製的概念  淺度複製:原始類型為值傳遞,物件類型仍為引用傳遞。  深度複製:所有元素或屬性均完全複製,與原對象完全脫離,也就是說所有對於新對象的修改都不會反映到原對象中。 三、淺複製的表現1,原始類型  看下面一段代碼:
//數值複製的表現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);// trueconsole.log(y);// false

從上面的代碼大家可以看出,原始類型即使我們採用普通的複製方式仍能得到正確的結果,原因就是原始類型儲存的是對象的實際資料。

2.物件類型  函數式一等對象,當然也是物件類型,但是函數的複製通過淺複製即可實現
var m=function(){alert(1);};var n=m;n=function(){alert(2);}; console.log(m());//1console.log(n());//2
  大家能看到,直接通過普通賦值的方式,就實現了函數的複製,並且不會影響之前的對象。原因就是函數的複製會在記憶體單獨開闢一塊空間,互不影響。   為了方便後續的代碼錶現,這裡定義一個複雜的物件類型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);//beijingoNew.oAddress.province="shanghai";console.log(oPerson.oAddress.province);//shanghai
  通過上面的代碼,可以看到,經過對象複製以後,修改oNew的地址,發現原對象oPerson也被修改了。這說明對象的複製不夠徹底,那也就是說深度複製失敗! 四、深複製的實現  為了保證對象的所有屬性都被複製到,我們必須知道如果for迴圈以後,得到的元素仍是Object或者Array,那麼需要再次迴圈,直到元素是原始類型或者函數為止。為了得到元素的類型,我們定義一個通用函數,用來返回傳入對象的類型。
//返回傳遞給他的任意對象的類function isClass(o){    if(o===null) return "Null";    if(o===undefined) return "Undefined";    return Object.prototype.toString.call(o).slice(8,-1);}
  PS:Object.prototype.toString.call(o)能直接返回對象的類屬性,形如"[object Number]"的字串,通過截取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);//pictureconsole.log(oPerson.ofavorite[1].reading);//history book oNew.oAddress.province="shanghai";console.log(oPerson.oAddress.province);//beijingconsole.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"}

javascript對象的深度複製

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.