該文轉載自http://www.cnblogs.com/zichi/p/4568150.html,有部分修改。html
在聊JavaScript(如下簡稱js)深度克隆以前,咱們先來了解一下js中對象的組成。
在 js
中一切實例皆是對象,具體分爲 原始類型 和 合成類型 :
原始類型 對象指的是 Undefined
、 Null
、Boolean
、Number
和 String
,按值傳遞。
合成類型 對象指的是 array
、 object
以及 function
,按址傳遞,傳遞的時候是內存中的地址。 數組
克隆或者拷貝分爲2種: 淺度克隆 、 深度克隆 。
淺度克隆 :基本類型爲值傳遞,對象仍爲引用傳遞。
深度克隆 :全部元素或屬性均徹底克隆,並於原引用類型徹底獨立,即,在後面修改對象的屬性的時候,原對象不會被修改。 函數
又或許你剛據說「深度克隆」這個詞,簡單來講,就是說有個變量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
的深度複製彷佛和原始數據類型的深度複製同樣。.net
var a = function () { console.log(1); }; var b = a; a = function () { console.log(2); }; b(); // 1
原本我也是這麼認爲的,直到文章下出現了評論。思考後我以爲 function
和普通的對象同樣,只是咱們在日常應用中習慣了總體的從新賦值,致使它在深度複製中的表現和原始類型一致:prototype
var a = function () { console.log(1); }; a.tmp = 10; var b = a; a.tmp = 20; console.log(b.tmp); // 20
因而乎對於 function
類型的深度克隆,直接賦值彷佛並不該該是一種最好的方法(儘管實際應用中足矣)。code
可是對象呢?htm
var a = [0,1,2,3]; var b = a; a.push(4); console.log(b); // [0, 1, 2, 3, 4]
顯然與預期不符,爲何會這樣?由於原始數據類型儲存的是對象的實際數據,而對象類型存儲的是對象的引用地址。上面的例子呢也就是說a和b對象引用了同一個地址,不管改變a仍是改變b,其實根本操做是同樣的,都是對那塊空間地址中的值的改變。對象
因而咱們知道了,對於基本的對象來講,不能只能用 「 = 」 賦值,思索後寫下以下代碼:blog
// 判斷arr是否爲一個數組,返回一個bool值 function isArray (arr) { return Object.prototype.toString.call(arr) === '[object Array]'; } // 深度克隆 function deepClone (obj) { if(typeof obj !== "object" && typeof obj !== 'function') { return obj; //原始類型直接返回 } var o = isArray(obj) ? [] : {}; for(i in obj) { if(obj.hasOwnProperty(i)){ o[i] = typeof obj[i] === "object" ? deepClone(obj[i]) : obj[i]; } } return o; }
注意代碼中判斷數組的時候用的不是 obj instanceof Array
,這是由於該方法存在一些小問題,詳情見 http://www.nowamagic.net/librarys/veda/detail/1250
用一些代碼來測試下:
// 測試用例: var srcObj = { a: 1, b: { b1: ["hello", "hi"], b2: "JavaScript" } }; var abObj = srcObj; var tarObj = cloneObject(srcObj); srcObj.a = 2; srcObj.b.b1[0] = "Hello"; console.log(abObj.a); console.log(abObj.b.b1[0]); console.log(tarObj.a); // 1 console.log(tarObj.b.b1[0]); // "hello"
彷佛能夠解決通常的對象(包括 Array
)的深度克隆了,或許這兒會有疑問,new String(..)
這類的也是對象啊,但是這樣寫你克隆不了啊…可是樓主以爲深度克隆的考點不在這裏,可能在於:
原始數據類型的直接賦值
function的exception
對象的深度克隆中Array類型的判斷
克隆函數的遞歸調用