1. 程式人生 > >js中物件、陣列的深拷貝

js中物件、陣列的深拷貝

通常我們對陣列、物件、物件陣列進行簡單賦值運算只是建立了一份原內容的引用,指向的仍然是同一塊記憶體區域,修改時會對應修改原內容,而有時候我們並不需要這種模式,這就需要對內容進行深拷貝。

一、陣列的深拷貝

方法1:遍歷複製

var arr = ["a", "b"], arrCopy = [];
for (var item in arr){
 arrCopy[item] = arr[item];
}
arrCopy[1] = "c";
arr   // => ["a", "b"]
arrCopy   // => ["a", "c"]

多維陣列可以寫成函式的方式:

function arrDeepCopy(source){
    var sourceCopy = [];
    for (var item in source) {
        sourceCopy[item] = typeof source[item] === 'object' ?                 
     arrDeepCopy(source[item]) : source[item];
    }
    return sourceCopy;
}

方法2:slice()

該方法並不會修改陣列,而是返回一個子陣列。

var arr = ["a", "b"];
arrCopy = arr.slice(0);
arrCopy[1] = "c";
arr   // => ["a", "b"] 
arrCopy   // => ["a", "c"]

方法3:contat()

該方法不會改變現有的陣列,而僅僅會返回被連線陣列的一個副本。

var arr = ["a", "b"];
arrCopy = arr.concat();
arrCopy[1] = "c";
arr   // => ["a", "b"] 
arrCopy   // => ["a", "c"]

二、物件的深拷貝

方法1:

var objDeepCopy = function(source){
    var sourceCopy = {};
    for (var item in source) sourceCopy[item] = typeof source[item] === 'object' ? objDeepCopy(source[item]) : source[item];
    return sourceCopy;
}
var objCopy = objDeepCopy(obj);
objCopy.a.a1[1] = "a13";
obj   // => { "a": { "a1": ["a11", "a12"], "a2": 1 }, "b": 2 }
objCopy   // => { "a": { "a1": ["a11", "a13"], "a2": 1 }, "b": 2 }

方法2:簡單粗暴,JSON.parse(JSON.stringify(obj));

JSON.stringify()  

1)object引數:是要轉為字串的JSON物件。
 2)replacer引數:可選,這個引數是一個過濾器,可以是改變字串轉換過程的函式,也可以是一組String和Number對 象。 這些物件用作一個白名單,用於選擇要轉換為字串的物件的屬性。如果這個值是空或沒有提供,則在所得的JSON字串中包含物件的所有屬性。

如果過濾器引數是一個數組,那麼JSON.stringify()的結果中將只包含陣列中列出的屬性。陣列元素與將要序列化的物件中的屬性是對應的,因此在返回的結果字串中,就只會包含這兩個屬性。

如果第二個引數是函式,那麼結果就會稍有不同。傳入的函式接收兩個引數,屬性名和屬性值。根據屬性名就可以知道應該如何處理要序列化的物件中的屬性。屬性名只能是字串,而在值並非鍵值對結構的值時,鍵名可以是空字串。

 3)space引數:可選,是一個String或Number物件,用於把空白插入輸出的JSON字串,以提高可讀性。如果這是一個數值,則表示用作空白的空格字元數;如果該數值大於10,就取其值為10;小於1的值表示不應使用空格。如果這是一個字串(如果該字串多於10個字元,就取前10個字元),就把該字串用作空白。如果沒有提供這個引數(或者為空),就不使用空白。

JSON.parse()

 引數
       1)text:必需。 一個有效的 JSON 字串。
       2)reviver:可選。 一個轉換結果的函式,這個函式被稱為還原函式,這個函式接收兩個引數,一個鍵和一個值。 將為物件的每個成員呼叫此函式。 如果成員包含巢狀物件,則先於父物件轉換巢狀物件。 對於每個成員,會發生以下情況:


如果 reviver 返回一個有效值,則成員值將替換為轉換後的值。
如果 reviver 返回它接收的相同值,則不修改成員值。
如果 reviver 返回undefined,則刪除成員。(我在FF和chrome下試驗的是返回undefined後,會刪除成員,返回null,只會賦值為null)
 

三、物件陣列的深拷貝

var objDeepCopy = function (source) {
    var sourceCopy = source instanceof Array ? [] : {};
    for (var item in source) {
        sourceCopy[item] = typeof source[item] === 'object' ? objDeepCopy(source[item]) : source[item];
    }
    return sourceCopy;
}
var objCopy = objDeepCopy(obj);
objCopy[0].a.a1[1] = "a13";
objCopy[1][1].e = "6";
obj   // => [{ "a": { "a1": ["a11", "a12"], "a2": 1 }, "b": 2 }, ["c", { "d": 4, "e": 5 }]]
objCopy   // => [{ "a": { "a1": ["a11", "a13"], "a2": 1 }, "b": 2 }, ["c", { "d": 4, "e": 6 }]]