淺拷貝(shellow copy)
先看下邊一個例子:
Object.prototype.clone = function () { var newObj = {}, self = this; for (var i in self) { newObj[i] = self[i]; } return newObj; } var obj = { name:"老李頭", hobby:["敲代碼","壓馬路"] } var _obj = obj.clone(); obj.hobby.push("打籃球"); console.log(obj.hobby);//["敲代碼", "壓馬路", "打籃球"] console.log(_obj.hobby);//["敲代碼", "壓馬路", "打籃球"]
就像我們看到的,淺拷貝只能復制基本類型的屬性,而對於共享對象類型的屬性則沒有辦法。
深拷貝 (deep copy)
在使用深拷貝復制對象時,由於數據類型的不確定性,可能為對象,數組,函數,也可能是以上幾種的嵌套。這個時候我們就需要借助遞歸。
Object.prototype.clone = function () { var self = this, newObj = {}; for(var i in self ){ if( typeof (self[i]) == "object" || typeof (self[i]) == "function"){ newObj[i] = self[i].clone(); }else{ newObj[i] = self[i]; } } return newObj; } Array.prototype.clone = function () { var self = this, newArr = []; for(var i=0,len=self.length;i<len;i++){ if( typeof (self[i]) == "object" || typeof (self[i]) == "function"){ newArr [i] = self[i].clone(); }else{ newArr [i] = self[i]; } } return newArr; } Function.prototype.clone = function () { var self = this, newFn = function () { return self.apply(this,arguments); }; for(var i in self){ newFn[i] = self[i]; } return newFn; } var obj = { name: 'byvoid', likes: ['node'], display: function() { console.log(this.name); }, }; var newObj = obj.clone(); newObj.likes.push('python'); console.log(obj.likes); // 輸出 [ 'node' ] console.log(newObj.likes); // 輸出 [ 'node', 'python' ] console.log(newObj.display == obj.display); // 輸出 false
上面這個實現看起來很完美,它不僅遞歸地復制了對象復雜的結構,還實現了函數的深拷貝。這個方法在大多數情況下都很好用,但有一種情況它卻無能為力,例如下面的代碼:
var obj1 = { ref:null }; var obj2 = { ref:obj1 }; obj1.ref = obj2;
這段代碼的邏輯非常簡單,就是兩個相互引用的對象。當我們試圖使用深拷貝來復制obj1 和 obj2 中的任何一個時,問題就出現了。因為深拷貝的做法是遇到對象就進行遞歸復制,那么結果只能無限循環下去。對於這種情況,簡單的遞歸已經無法解決。