Js實現深淺複製
阿新 • • 發佈:2020-12-10
為什麼有深複製、淺複製?
JavaScript中有兩種資料型別,基本資料型別如undefined、null、boolean、number、string,另一類是Object。簡單資料型別只儲存在記憶體中的棧區,複製的時候是值傳遞給新的索引。而複雜資料型別由棧區和堆區共同儲存,棧區執行同樣的操作,只是把堆地址複製了一份,而真實資料在堆區中依然只有一份。
為了不影響原有資料,那麼我們就新建一個物件,遍歷原有物件的屬性賦值到新屬性。
let newObj = {}
for (let prop in obj) {
newObj[prop] = obj[prop]
}
上面這個迴圈也可以用Object.assign({}, obj);來實現。
這樣做是否解決問題?未必,因為Object中可以巢狀Object,如果原有物件屬性中有複雜資料型別,那麼新的物件中也只能得到一個地址。這種情況被稱為淺複製
深複製的幾種方法
首先假設有資料
let obj = {
a: 23,
b: [0, 1, [2, 3], function() {console.log('in array')}, undefined],
c: {k: 'value'},
d: function() {console.log('a')}
}
jsON.parse(jsON.stringify(obj))
let newObj = JSON.parse(JSON.stringify(obj))
newObj.newKey = 'newValue'
console.log(obj)
console.log(newObj)
如果處理物件只是簡單的鍵值對,這個方法效果不錯。
這個方法的缺點
- 無法複製函式
- 忽略undefined值
- 無法處理Set、Map、Symbol型別(即使用上repalce引數)
- 原有的原型鏈會消失
-
迴圈引用的物件會報錯
遞迴法
因為要處理屬性的值也是Object這種情況,自然可以想到遞迴這種處理方法。
function deepCopy(oldObj, newObj) {
let obj = newObj || {}
for (let i in oldObj) {
if (oldObj[i] === obj) { // 防止迴圈引用
continue
}
if (typeof oldObj[i] === 'object') {
// obj[i] = (oldObj[i].const ructor === Array) ? [] : {}
obj[i] = oldObj[i] instanceof Array ? [] : {}
deepCopy(oldObj[i], obj[i])
} else {
obj[i] = oldObj[i]
}
}
return obj;
}
這樣就能處理一個嵌套了Object和Array等複雜變數的物件。但是物件中還可能包含Date和RegExp物件、Set、Map……
Lodash庫
const lodash = require('lodash')
let newObj = lodash.cloneDeep(obj)
資源搜尋網站大全 https://www.renrenfan.com.cn 廣州VI設計公司https://www.houdianzi.com
陣列的複製
let arr = [1, 2, 3, [4, 5], {a: 1}]
let copy = arr
copy.push(6)
let copy1 = [...arr]
copy1.push(999)
let copy2 = Array.from(arr)
copy2.push(888)
let copy3 = arr.slice()
copy3.push(777)
// 以上方法都是淺拷貝
arr[4].a = 2
console.log(arr) // [ 1, 2, 3, [ 4, 5 ], { a: 2 }, 6 ]
console.log(copy1) // [ 1, 2, 3, [ 4, 5 ], { a: 2 }, 6 ]
console.log(copy2) // [ 1, 2, 3, [ 4, 5 ], { a: 2 }, 6, 888 ]
console.log(copy3) // [ 1, 2, 3, [ 4, 5 ], { a: 2 }, 6, 777 ]