js實現深拷貝(深度克隆)
阿新 • • 發佈:2020-07-29
淺克隆(淺拷貝)
在資料型別為引用型別的時候,當你給這個變數賦值,其實是引用這個變數在記憶體中的地址。如下:
var obj = {name: 'ccc', age: 18} // 定義一個變數為物件,引用型別
var cloneObj = obj // 建立一個新變數,並賦值
console.log(cloneObj) // {name: 'ccc', age: 18}
console.log(cloneObj === obj) // true
淺克隆帶來的問題:
var obj = {name: 'ccc', age: 18} // 定義一個變數為物件,引用型別 var cloneObj = obj // 建立一個新變數,並賦值 console.log(cloneObj) // {name: 'ccc', age: 18} console.log(cloneObj === obj) // true obj.name = 'www' console.log(cloneObj) // { name: 'www', age: 18 }
我們可以發現,我們修改了obj變數的屬性值的時候,cloneObj的屬性值也跟著發生了變化。原因是他們雖然是兩個變數,但是引用的變數是同一個變數。看下圖分析:
深度克隆(深拷貝)
深度克隆,就是解決淺度克隆帶來的問題的。直接上程式碼:
function deepClone(o) { // 判斷如果不是引用型別,直接返回資料即可 if (typeof o === 'string' || typeof o === 'number' || typeof o === 'boolean' || typeof o === 'undefined') { return o } else if (Array.isArray(o)) { // 如果是陣列,則定義一個新陣列,完成複製後返回 // 注意,這裡判斷陣列不能用typeof,因為typeof Array 返回的是object console.log(typeof []) // --> object var _arr = [] o.forEach(item => { _arr.push(item) }) return _arr } else if (typeof o === 'object') { var _o = {} for (let key in o) { _o[key] = deepClone(o[key]) } return _o } } var arr = [1, 2, 3, 5] var cloneArr = deepClone(arr) console.log(cloneArr) // --> [ 1, 2, 3, 5 ] console.log(arr === cloneArr) // --> false var obj = { name: 'ccc', age: 18 } var cloneObj = deepClone(obj) console.log(cloneObj) // --> { name: 'ccc', age: 18 } console.log(obj === cloneObj) // false obj.name = 'www' console.log(obj) // --> { name: 'www', age: 18 } console.log(cloneObj) // --> { name: 'ccc', age: 18 }
obj和cloneObj分別指向自己所存的變數地址,互不影響,程式碼註釋挺詳細了,看下圖:
注意:上圖深度克隆程式碼只供參考瞭解,還有很多細節沒有考慮,比如陣列和物件的巢狀拷貝等等,具體使用請檢視Lodash中的cloneDeep()方法。