引用型別賦值給另一個(gè)引用型別,它們只是都是指向的同一個(gè)位址,操作間會(huì)互相影響。
深拷貝,就是重新分配空間,讓它跟著之前的物件或陣列不受影響。
淺拷貝就是等同於引用型別的賦值。
var a={banner:{size:1,weight:'0.5kg'}};
var b={apple:{size:1},banner:{size:3}};
$.extend(true,a,b)=>{banner:{size:3,weight:'0.5kg'},apple:{size:1}};
$.extend(a,b)=>{banner:{size:3},apple:{size:1}};
我看過(guò)jquery源碼,深拷貝是要進(jìn)行遞歸的。
但是我不理解,跟互相影響有什麼關(guān)係,還是說(shuō)我上面的概念理解錯(cuò)誤
學(xué)習(xí)是最好的投資!
淺拷貝
僅對(duì)object頂層鍵進(jìn)行遍歷和重新賦值(給對(duì)應(yīng)的引用),例如:
var a = {
x: {
name: 'x',
value: 10,
},
y: 10,
o: {},
}
var b = {
x: {
name: 'x2',
value: 20,
},
y: {
name: 'y2',
value: 20,
},
z: {}
}
$.extend(a, b)
這個(gè)過(guò)程裡面,從b中取出所有頂層元素,即b.x, b.y, b.z,然後將它們一一賦值給a對(duì)應(yīng)的鍵,所以最後a就有了新的a.x, a.y, a.z,同時(shí),a.o還保留在a中,這時(shí)a.x === b.x, a.y === b.y, a.z === b.z,因?yàn)樗鼈兌际侵赶蛲粋€(gè)物件的引用。既然是引用,當(dāng)你操作a.x的時(shí)候,例如a.x.name = 'x3',那麼b.x.name也變成了'x3'。
深拷貝
深拷貝將深入物件元素的末層進(jìn)行重新賦值,而非引用。就拿上面的a,b舉例,執(zhí)行:
$.extend(true, a, b)
將會(huì)深入b內(nèi)部進(jìn)行遍歷,拿每一個(gè)節(jié)點(diǎn)的值與a對(duì)應(yīng)(一模一樣)的節(jié)點(diǎn)進(jìn)行比較,如果不同則為a開(kāi)闢儲(chǔ)存空間,把值賦進(jìn)去,如果a不存在這個(gè)節(jié)點(diǎn),就為它創(chuàng)建後賦值進(jìn)去。 a的第一層子節(jié)點(diǎn)跟b第一層不存在相等關(guān)係,連==都不成立。
深拷貝後,a原有的一些節(jié)點(diǎn)會(huì)保留下來(lái),b給過(guò)去的節(jié)點(diǎn)會(huì)覆蓋或增加,但是和b之間不存在任何引用關(guān)係,所以修改a的任何一個(gè)節(jié)點(diǎn),都不會(huì)影響b。這在一些數(shù)據(jù)處理的時(shí)候非常有用,為了不影響原始數(shù)據(jù),需要在處理數(shù)據(jù)之前深拷貝一份再進(jìn)行處理。
深拷貝的時(shí)候,陣列的索引號(hào)碼被當(dāng)作鍵名對(duì)待,所以陣列元素會(huì)被修改,而不是被加入到原始資料中。如:
var a = [
{
x: 1,
},
{
x: 2,
},
]
var b = [
{
y: 2
},
]
$.extend(true, a, b)
將會(huì)得到:
var a = [
{
x: 1,
y: 2
},
{
x: 2,
},
]
b的第一個(gè)原始被合併到a的第一個(gè)元素裡面去了,這個(gè)合併是因?yàn)閿?shù)組按照元素的索引號(hào)作為鍵來(lái)操作。所以,合併數(shù)組不能用extend,而應(yīng)該考慮用merge或concat。