在JavaScript很多人復制一個對象的時候都是直接用"=",因為大家都覺得腳本語言是沒有指針、引用、地址之類的,所以直接用"="就可以把一個對象復制給另外一個對象,如下代碼:
var i1 = 1; var i2 = i1; i2 = 2; alert("i1:"+i1+",i2:"+i2);
輸出結果:i1:1 , i2:2
但可能沒有發現,這種“復制”用在對象(object)類型是“錯誤”的,因為這只是把對象的地址復制,所以如下代碼會進行了一次“錯誤”的復制:
代碼2
var o1 = {i : 1,s : "o1"}; var o2 = o1; o2.i=2; o2.s="o2"; alert("o1.i:"+o1.i+",o2.i:"+o2.i); alert("o1.s:"+o1.s+",o2.s:"+o2.s);
輸出:o1.i:2 , o2.i:2
o1.s:o2 , o2.s:o2
可能你會問為什么 代碼1 可以復制,但 代碼2 卻沒有復制?
其實准確來說是“基本數據類型”可以復制,非基本類型(包括字符串)只復制其引用。為什么要這樣做呢?原因很簡單,為了減少開銷。大家都知道非基本類型有時候很大,如果重新開辟內存來存放一個這么大的對象,開銷很大,導致運行會很慢。腳本語言是直接在虛擬機(或者瀏覽器)運行,它經過虛擬機這一層來處理代碼,速度已經相對其他編譯語言慢很多,所以如果把非基本對象再做“復制”,那么可能你要等上一年半載才能運行得了程序,因此只能復制對象的引用。
但很多時候我們並不希望函數去修改我們的這些對象參數,這就需要使用到對象的克隆,我們應該對該對象做一個克隆,然后操作這個克隆的對象,這樣就不會影響我們的原對象了。 如果需要把整個對象復制,必須一個一個屬性或方法引用復制一偏,這樣為每個屬性開辟內存來存放你需要的數據,當然這樣相對來說會很慢,尤其數據量很多的時候, 在js中並沒有對象克隆功能,因此需要我們自己實現,實現方法也不復雜,基本上是做一些屬性復制,我在網上找了一些,但有些實現並不好,如對於array對象克隆后就成json對象了,並沒有保留原來的數組方式。不過最后還是找到了一個很好的克隆函數,完美實現了js對象的克隆功能,不論是Array對象或者是普通的Object,都可以很好的進行克隆,這個函數使用constructor(函數構造器)進行復制。
方法一:
Object.prototype.Clone = function(){ var objClone; if (this.constructor == Object){ objClone = new this.constructor(); }else{ objClone = new this.constructor(this.valueOf()); } for(var key in this){ if ( objClone[key] != this[key] ){ if ( typeof(this[key]) == 'object' ){ objClone[key] = this[key].Clone(); }else{ objClone[key] = this[key]; } } } objClone.toString = this.toString; objClone.valueOf = this.valueOf; return objClone; }
方法二:
function clone(obj){ var o; switch(typeof obj){ case 'undefined': break; case 'string' : o = obj + '';break; case 'number' : o = obj - 0;break; case 'boolean' : o = obj;break; case 'object' : if(obj === null){ o = null; }else{ if(obj instanceof Array){ o = []; for(var i = 0, len = obj.length; i < len; i++){ o.push(clone(obj[i])); } }else{ o = {}; for(var k in obj){ o[k] = clone(obj[k]); } } } break; default: o = obj;break; } return o; }
方法三:
function clone3(obj){ function Clone(){} Clone.prototype = obj; var o = new Clone(); for(var a in o){ if(typeof o[a] == "object") { o[a] = clone3(o[a]); } } return o; }
方法四:
arrayObj=[1,2,3,4,5];
arrayObj.slice(0); //返回數組的拷貝數組,注意是一個新的數組,不是指向 arrayObj.concat(); //返回數組的拷貝數組,注意是一個新的數組,不是指向