歡迎光臨
每天分享高質量文章

如何實現物件的深度克隆

前端筆試或者面試的時候,很喜歡問的一個問題就是物件的深度克隆,或者說是物件的深度複製。其實這個問題說容易很容易,但是要說全面也挺不易。

要弄明白物件的克隆,首先要明白js中物件的組成。在js中一切實體皆是物件,具體分為原始型別和合成型別。原始型別物件指的是number、string、boolean等,合成型別物件指的是array、object以及function。

又或許你剛聽說“深度克隆”這個詞,簡單來說,就是說有個變數a,a的值是個物件(包括基本資料型別),現在你要創建一個變數b,使得它擁有跟a一樣的方法和屬性等等。但是a和b之間不能相互影響,即a的值的改變不影響b值的變化。

直接賦值可好?

var a = 1;

var b = a;

a = 10;

console.log(b);

// 1

var a = ‘hello’;

var b = a;

a = ‘world’;

console.log(b);

// hello

var a = true;

var b = a;

a = false;

console.log(b);

// true

實踐證明某些JavaScript的原始資料型別,如果要克隆直接賦值即可。

關於function的深度複製:查閱了一些資料,function的深度複製似乎和原始資料型別的深度複製一樣。

var a = function() {console.log(1);};

var b = a;

a = function() {console.log(2);};

b();

// 1

本來我也是這麼認為的,直到文章下出現了評論。思考後我覺得function和普通的物件一樣,只是我們在平常應用中習慣了整體的重新賦值,導致它在深度複製中的表現和原始型別一致:

var a = function() {console.log(1);};

a.tmp = 10;

var b = a;

a.tmp = 20;

console.log(b.tmp);

// 20

於是乎對於function型別的深度克隆,直接賦值似乎並不應該是一種最好的方法(儘管實際應用中足矣)。那麼如何克隆?可以參考文章下麵的評論,不失為一種解決方案。

但是物件呢?

var a = [0, 1, 2, 3];

var b = a;

a.push(4);

console.log(b);

// [0, 1, 2, 3, 4]

顯然與預期不符,為什麼會這樣?因為原始資料型別儲存的是物件的實際資料,而物件型別儲存的是物件的取用地址。上面的例子呢也就是說a和b物件取用了同一個地址,無論改變a還是改變b,其實根本操作是一樣的,都是對那塊空間地址中的值的改變。

於是我們知道了,對於基本的物件來說,不能只能用=賦值,思索後寫下如下代碼:

function deepClone(obj) {

var o = obj instanceof Array ? [] : {};

for(var k in obj)

o[k] = typeof obj[k] === Object ? deepClone(obj[k]) : obj[k];

return o;

}

var a = [[1, 2, 3], [4, 5, 6, 7]];

var b = deepClone(a);

console.log(b);

似乎可以解決一般的物件(包括Array)的深度克隆了,或許這兒會有疑問,new String(..)這類的也是物件啊,可是這樣寫你克隆不了啊…但是樓主覺得深度克隆的考點不在這裡,可能在於:

  1. 原始資料型別的直接賦值

  2. function的exception

  3. 物件的深度克隆中Array型別的判斷

  4. 克隆函式的遞迴呼叫

來自:韓子遲

鏈接:http://www.cnblogs.com/zichi/p/4568150.html


赞(0)

分享創造快樂