JS深拷貝詳解
1.這里實(shí)現(xiàn)了深拷貝是因?yàn)樵诨緮?shù)據(jù)類型String Number 都可以實(shí)現(xiàn)深拷貝因?yàn)樗挥幸粚?,且每次改變的變量的值都是改變整個(gè)變量這樣在堆中又開辟了一個(gè)內(nèi)存空間,沒(méi)有嵌套的情況下直接修改整個(gè)變量的方法在對(duì)象和方法中也適用
var a = 1
var b = a
a 打印結(jié)果為 1
b 打印結(jié)果為 1
a = 2
a 打印結(jié)果為 2
b 打印結(jié)果為 1
2.這里實(shí)現(xiàn)了深拷貝的原因與第1條是一樣的,因?yàn)楦某蒩變量整個(gè)值,所以在堆中又開辟了一個(gè)新空間
var a = [1,2,3]
var b = a
a 打印結(jié)果為 (3) [1, 2, 3]
b 打印結(jié)果為 (3) [1, 2, 3]
a = [3,2,1]
a 打印結(jié)果為 (3) [3, 2, 1]
b 打印結(jié)果為 (3) [1, 2, 3]
3.這里沒(méi)有實(shí)現(xiàn)深拷貝是因?yàn)?這里的a是引用數(shù)據(jù)類型萄唇,且修改a的值時(shí)改變的是下標(biāo)0的數(shù)據(jù),并沒(méi)有整個(gè)a變量全部修改术幔,所以并沒(méi)有開辟新的內(nèi)存空間另萤,導(dǎo)致a和b都指向了同一個(gè)堆,故而打印的結(jié)果是一樣的
var a = [1,2,3]
var b = a
a 打印結(jié)果為 (3) [1, 2, 3]
b 打印結(jié)果為 (3) [1, 2, 3]
a[0] = 2
a 打印結(jié)果為 (3) [2, 2, 3]
b 打印結(jié)果為 (3) [2, 2, 3]
4.這里實(shí)現(xiàn)了深拷貝是因?yàn)榻ob賦值的時(shí)候使用了擴(kuò)展運(yùn)算符诅挑,這樣就等于為b在堆里面新開了一個(gè)內(nèi)存空間四敞,故而實(shí)現(xiàn)了深拷貝
var b = [...a]
a 打印結(jié)果為 (3) [1, 2, 3]
b 打印結(jié)果為 (3) [1, 2, 3]
a[0] = 2
a 打印結(jié)果為 (3) [2, 2, 3]
b 打印結(jié)果為 (3) [1, 2, 3]
##5.這里使用了擴(kuò)展運(yùn)算符但是卻沒(méi)有像第4條那樣實(shí)現(xiàn)深拷貝,因?yàn)檫@里的a是二維數(shù)組拔妥,a和b下標(biāo)為3的數(shù)據(jù)來(lái)源于同一個(gè)堆忿危,故而打印結(jié)果為一樣
```var a = [1,2,3,[4,5]]
var b = [...a]
a 打印結(jié)果為 [0:1,1:2,2:3,3:[0:4,1:5]]
b 打印結(jié)果為 [0:1,1:2,2:3,3:[0:4,1:5]]
a[3][0] = 6
a 打印結(jié)果為 [0:1,1:2,2:3,3:[0:6,1:5]]
b 打印結(jié)果為 [0:1,1:2,2:3,3:[0:6,1:5]]
#根據(jù)以上結(jié)論我們得出結(jié)論:
1. 無(wú)論是不是使用了擴(kuò)展運(yùn)算符只要是直接修改了a變量整體數(shù)據(jù)那就不影響b,因?yàn)樽兞空w修改的話相當(dāng)于在堆里面新開辟了一個(gè)內(nèi)存
2. 擴(kuò)展運(yùn)算符支持深拷貝只建立在沒(méi)有嵌套數(shù)據(jù)的情況下毒嫡。
下面我們來(lái)說(shuō)遇到多層嵌套的情況下怎么進(jìn)行深拷貝
##1. 使用JSON.stringify轉(zhuǎn)換為JSON字符串 后使用JSON.parse解析為JS的對(duì)象或值
```var a = [1,2,3,[4,5]]
var b = JSON.parse(JSON.stringify(a))
a 打印結(jié)果為 [0:1,1:2,2:3,[0:4,1:5]]
b 打印結(jié)果為 [0:1,1:2,2:3,[0:4,1:5]]
a[3][1] = 11
a 打印結(jié)果為 [0:1,1:2,2:3,[0:4,1:11]]
b 打印結(jié)果為 [0:1,1:2,2:3,[0:4,1:5]]
##2.但是需要注意的是癌蚁,JSON.stringify無(wú)法深拷貝函數(shù)幻梯。如下代碼
```var a = {function(){console.log('hello')}}
a 打印結(jié)果為 {function: ?}
var b = JSON.parse(JSON.stringify(a))
b 打印結(jié)果為 {}
##3.這個(gè)時(shí)候我們就需要用到遞歸遍歷對(duì)象并手動(dòng)進(jìn)行拷貝 或者 Lodash的_.cloneDeep方法 兜畸。函數(shù)序列化并還原是相當(dāng)復(fù)雜的操作,并且有安全風(fēng)險(xiǎn)碘梢,因?yàn)檫€原的函數(shù)將在不受控制的上下文中執(zhí)行咬摇。應(yīng)謹(jǐn)慎使用和處理包含函數(shù)的序列化數(shù)據(jù)
```const _ = require('lodash');
const obj = { func: function() { console.log('Hello!'); } };
const clonedObj = _.cloneDeep(obj);
console.log(clonedObj);
// 輸出: { func: [Function: func] }