JavaScript中的深度克隆

javascript的一切實例都是對象,只是對象之間稍有不同,分爲原始類型和合成類型。原始類型對象指的是字符串(String)、數值(Number)、布爾值(Boolean),合成類型對象指的是數組(Array)、對象(Object)、函數(Function)。

既然對象分爲這兩類,他們之間的最大差別是複製克隆的差別。普通對象存儲的是對象的實際數據,而引用對象存儲的是對象的引用地址,而把對象的實際內容單獨存放,因爲引用對象通常比較龐大,這是數據開銷和內存開銷優化的手段。通常初學者很難理解這部分內容,就像對象的原型一樣,也是同一個概念。對象的原型也是引用對象,把原型的方法和屬性放在單獨內存當中,而對象的原型鏈則指向這個內存地址。儘管這部分內容比較拗口複雜,那其中的原理都是一致的,目的也一致。

1、原始類型對象的克隆

1.1、字符串的克隆

var x="1";
var y=x;
y="2"; 
// "1"
alert(x);
// "2"
alert(y);

1.2、數值的克隆

var x=1;
var y=x;
y=2; 
// 1
alert(x);
// 2
alert(y);

1.3、布爾值的克隆

var x=true;
var y=x;
y=false;
 // true
alert(x);
// false
alert(y);

2、合成類型對象的克隆

2.1、數組的克隆

如果採用普通克隆:

var x=[1,2];
var y=x;
y.push(3); 
// 1,2,3
alert(x); 
// 1,2,3
alert(y);

由上可知,原始數組x,克隆數組y,修改了克隆數組y,但也同時修改了原始數組x,這就是引用對象的特點。那麼如何才能達到完整的數組克隆呢?

var x=[1,2];
var y=[];
var i=0;
var j=x.length;
for(;i<j;i++){	
    y[i]=x[i];
}
y.push(3); 
// 1,2
alert(x); 
// 1,2,3
alert(y);

這樣,克隆數組y,原始數組x,兩個數組互補干擾,實現了完整的數組克隆。

2.2、對象的克隆

和數組的克隆同理,對象的完整克隆如下:

var x={1:2,3:4};
var y={};
var i;
for(i in x){	
    y[i]=x[i];
}
y[5]=6; 
// Object {1: 2, 3: 4} 
console.log(x); 
// Object {1: 2, 3: 4, 5: 6} 
console.log(y);

2.3、函數的克隆

var x=function(){alert(1);};
var y=x;
y=function(){alert(2);};

// function(){alert(1);};
alert(x);

// y=function(){alert(2);};
alert(y);

函數的克隆,使用“=”符號就可以了,並且在改變克隆後的對象,不會影響克隆之前的對象,因爲克隆之後的對象會單獨複製一次並存儲實際數據的,是真實的克隆。

3、完整的對象克隆

根據1和2,總結一下完整的對象克隆,包括克隆普通對象、引用對象。在寫這個方法之前,我們必須想到的是,克隆引用對象必須採用完整克隆(深度克隆),包括對象的值也是一個對象也要進行完整克隆(深度克隆)。

完整的對象克隆又稱爲深度對象克隆、對象的深度克隆、對象的深度複製等等。

  1. function clone(obj)
  2. {
  3.     var o,i,j,k;
  4.     if(typeof(obj)!="object" || obj===null)return obj;
  5.     if(obj instanceof(Array)){
  6.          //如果當前遍歷到的是數組的話
  7.          o=[];
  8.           i=0;j=obj.length;
  9.           for(;i<j;i++)
  10.           {
  11.                  if(typeof(obj[i])=="object" && obj[i]!=null)
  12.                  {
  13.                      o[i]=arguments.callee(obj[i]);
  14.                  }
  15.                 else
  16.                  {
  17.                      o[i]=obj[i];
  18.                  }
  19.            }
  20.     }
  21.     else
  22.     {
  23.    //如果當前遍歷到的是一個obj的話, 創建一個obj對象, 遍歷當前obj的屬性
  24.         o={};
  25.         for(i in obj){
  26. //遍歷當前obj的屬性
  27.             if(typeof(obj[i])=="object" && obj[i]!=null){
  28.                 o[i]=arguments.callee(obj[i]);
  29.             }
  30.             else{
  31.     //遍歷到obj內的屬性, 直接使用"="進行賦值操作即可
  32.                 o[i]=obj[i];
  33.              }
  34.          }
  35.      }
  36. return o;
  37. }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章