淺克隆(淺拷貝)
在數據類型為引用類型的時候,當你給這個變量賦值,其實是引用這個變量在內存中的地址。如下:
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()方法。