您好,登錄后才能下訂單哦!
小編今天帶大家了解如何分析web前端中的深拷貝和淺拷貝,文中知識點介紹的非常詳細。覺得有幫助的朋友可以跟著小編一起瀏覽文章的內(nèi)容,希望能夠幫助更多想解決這個問題的朋友找到問題的答案,下面跟著小編一起深入學習“如何分析web前端中的深拷貝和淺拷貝”的知識吧。
深拷貝和淺拷貝是經(jīng)常在面試中會出現(xiàn)的,主要考察你對基本類型和引用類型的理解深度。我在無數(shù)次的面試中,應(yīng)聘者還沒有一個人能把這個問題回答情況,包括很多機構(gòu)的培訓老師。這篇文章會讓你把基本類型和引用類型的區(qū)別搞得清清楚楚,搞清楚這兩者的區(qū)別,你對任何編程語言的都不怕,因為,這不是js一門語言,是任何編程語言中都需要掌握的知識,而且,在任何編程語言中,兩者都是一樣的。
深拷貝和淺拷貝主要是針對對象的屬性是對象(引用類型)
一、基本類型和引用類型的區(qū)別
1、先了解內(nèi)存
任何編程語言的內(nèi)存分區(qū)幾乎都是一樣的
內(nèi)存是存儲數(shù)據(jù)的,不同類型的數(shù)據(jù)要存儲在不同的區(qū)域,即分類存放,不同的區(qū)域作用和功能也不一樣。就像你家里的衣柜一樣,也分了不同的區(qū)域:如掛西裝的區(qū)域,放襪子的區(qū)域等等,我相信每個人都會把這兩個東西放在不同的區(qū)域。要不然,當你西裝革履地參加一個高檔的宴會,手塞在褲兜里,掏出來一只臭襪子,是不是很尷尬?。?!哈哈!??!
以下為內(nèi)存的分區(qū)圖。內(nèi)存分為四個區(qū)域:棧區(qū)(堆棧),堆區(qū),全局靜態(tài)區(qū),只讀區(qū)(常量區(qū)和代碼區(qū))。
https://blog.csdn.net/jiang7701037/article/details/98728249
2、基本類型和引用類型在內(nèi)存上存儲的區(qū)別
現(xiàn)在只看棧區(qū)和堆區(qū),不管其它區(qū)域,也假定只是局部變量。
以上函數(shù)testf在調(diào)用時,
1)、 定義局部變量 age,由于age是局部變量,所以在棧中申請內(nèi)存空間,起名為age,又由于給age賦的值250是基本類型,所以,值直接存儲在棧中。
2)、定義局部變量arr,由于arr是局部變量,所以在棧中申請空間,但是arr的內(nèi)存中存儲的是什么?由于給arr賦的值不是基本類型,而是引用類型(new出來的),所以,先在堆中申請空間存放數(shù)據(jù) 12,23,34,。再把堆區(qū)的地址賦給arr。
3、到底什么是基本類型和引用類型
1)、基本類型:就是值類型,即在變量所對應(yīng)的內(nèi)存區(qū)域存儲的是值,如:上面的age變量所對應(yīng)的內(nèi)存存儲的就是值250.
2)、引用類型:就是地址類型。
何為地址:地址就是編號,要地址何用,就是為了容易找到。每個人的家里為什么要有一個唯一的地址,就是在郵寄時,能夠找到你家。
比如:我們最早的超市存包的格子,每個格子都有個編號,你存包時,服務(wù)員會把你的東西放在某個格子里,再把這個格子的編號給你(一個牌子)。你購物完畢取包時,直接給服務(wù)員你的牌子(有編號),服務(wù)員根據(jù)你的編號就會找到你的包。這個編號就是格子的地址。內(nèi)存也是一樣的,每個內(nèi)存都有一個編號,方便cpu查找。要不然,浩瀚的內(nèi)存海洋,cpu要找到數(shù)據(jù)靠啥找。
以上的變量arr就是引用類型,arr所對應(yīng)的內(nèi)存中存儲著地址,真正的數(shù)據(jù)是在地址對應(yīng)的內(nèi)存區(qū)域里,就像,你填寫簡歷時,會在簡歷的那張紙上寫上你家的地址。簡歷上寫你家地址的地方就相當于arr。而你家是根據(jù)這個地址可以找到的。簡歷上寫你家地址的地方就相當于引用著你家(可以想象一根無形的線牽引著你家,在簡歷上的這根無形的線,順藤摸瓜就能找到你家)。所以叫做引用類型。
二、基本類型和引用類型在賦值時內(nèi)存的變化
你可以認為,賦值就是在拷貝。
1、基本類型:
2、引用類型:
如果給arr[0]賦值的話,arr1[0]的值也會發(fā)生變化,因為,arr和arr1保存著相同的地址,它門兩個引用的數(shù)據(jù)是共享的。就像你在很多地方(簡歷的那張紙,戶口本上的那張紙)會寫上你的家庭地址。這么多張紙都引用著你家。根據(jù)一張紙上找到你家,給你家放上一百萬的現(xiàn)金(數(shù)據(jù)改變了,相當于arr[0]=10),再根據(jù)另外一張紙的地址也找到了你家,你發(fā)現(xiàn)你一百萬在(不要給我說被人拿了)
如果在上面的基礎(chǔ)上增加一句代碼:arr[0]=10;那么內(nèi)存將會有如下變化:
三、基本類型和引用類型作為函數(shù)參數(shù)的區(qū)別(這個可以不看)
1、基本類型作為函數(shù)的參數(shù)
2、引用類型作為函數(shù)的參數(shù):
四、深拷貝和淺拷貝:
終于說到了深拷貝和淺拷貝。
其實在第二點已經(jīng)說到了拷貝,所謂拷貝,就是賦值。把一個變量賦給另外一個變量,就是把變量的內(nèi)容進行拷貝。把一個對象的值賦給另外一個對象,就是把一個對象拷貝一份。
1、基本類沒有問題,
因為,基本類型賦值時,賦的是數(shù)據(jù)(所以,不存在深拷貝和淺拷貝的問題)。
如:
Var x = 100;
Var y = x; //此時x和y都是100;
如果要改變y的值,x的值不會改變。
2、引用類型有問題
因為,引用類型賦值時,賦的值地址(就是引用類型變量在內(nèi)存中保存的內(nèi)容),強烈建議把前面的第二點(基本類型和引用類型在賦值時內(nèi)存的變化)多看幾遍,以保證理解深刻。這樣,一勞永逸,以后在碰到任何跟引用類型有關(guān)的話題(如:繼承時,父類的屬性是引用類型)都沒有問題。
如:
var arr1 = new Array(12,23,34)
Var arr2 = arr1;//這就是一個最簡單的淺拷貝
如果要改變arr2所引用的數(shù)據(jù):arr2[0]=100時,那么arr1[0]的值也是100。
原因就是 arr1和arr2引用了同一塊內(nèi)存區(qū)域(以上的第二點中有體現(xiàn))。
這是最簡單的淺拷貝,因為,只是把arr1的地址拷貝的一份給了arr2,并沒有把arr1的數(shù)據(jù)拷貝一份。所以,拷貝的深度不夠
3、用json對象的方式(也是引用類型)來演示淺拷貝和深拷貝
1)、定義一個json對象(對象的屬性也是對象)
00001.
var p = {
"id":"007",
"name":"劉德華",
"books":new Array("三國演義","紅樓夢","水滸傳")//這是引用類型
}
00002.
2)、把該對象p進行復(fù)制一份
· (一)淺拷貝
00001.
var p2 = {};
for(let key in p){
p2[key] = p[key];
}
p2.books[0] ="四國";
console.log(p2);
console.log(p);
00002.
在控制臺中打印的結(jié)果(p和p2的books[0]都變成了“四國”):
內(nèi)存:
(二) 深拷貝(初步)
var p2 = {};
for(let key in p){
if(typeof p[key]=='object'){
p2[key]=[];//因為,我上面寫的是數(shù)組,所以,暫時賦值一個空數(shù)組.
for(let i in p[key]){
p2[key][i] = p[key][i]
}
}else{
p2[key] = p[key];
}
}
p2.books[0] ="四國";
console.log(p2);
console.log(p);
在控制臺中打印的結(jié)果(只有p2的books[0]變成了“四國”)
內(nèi)存:
(三)深拷貝(最終)
3.1、深拷貝_如果屬性都是json對象,那么用遞歸的方式
//如果對象的屬性是對象(引用類型),屬性的屬性也是引用類型,即層層嵌套很多.怎么辦,只能遞歸
//如下對象,要復(fù)制:
00001.
var p = {
"id":"007",
"name":"劉德華",
"wife":{
"id":"008",
"name":"劉德的妻子",
"address":{
"city":"北京",
"area":"海淀區(qū)"
}
}
}
//寫函數(shù)
function copyObj(obj){
let newObj={};
for(let key in obj){
if(typeof obj[key] =='object'){//如:key是wife,引用類型,那就遞歸
newObj[key] = copyObj(obj[key])
}else{//基本類型,直接賦值
newObj[key] = obj[key];
}
}
return newObj;
}
let pNew = copyObj(p);
pNew.wife.name="張三瘋";
pNew.wife.address.city = "香港";
console.log(pNew);
console.log(p);
3.2、深拷貝_如果屬性是數(shù)組等非鍵值對的對象
就得單獨處理:要么給數(shù)組增加一個自我復(fù)制的函數(shù)(建議這樣做),要么單獨判斷。
```
//給數(shù)組對象增加一個方法,用來復(fù)制自己
Array.prototype.copyself = function(){
let arr = new Array();
for(let i in this){
arr[i] = this[i]
}
return arr;
}
var p = {
"id":"007",
"name":"劉德華",
"books":new Array("三國演義","紅樓夢","水滸傳")//這是引用類型
}
function copyObj(obj){
let newObj={};
for(let key in obj){
if(typeof obj[key] =='object'){//如:key是wife,引用類型,那就遞歸
newObj[key] = obj[key].copyself();
}else{//基本類型,直接賦值
newObj[key] = obj[key];
}
}
return newObj;
}
var pNew = copyObj(p);
pNew.books[0] = "四國";
console.log(pNew);
console.log(p);
```
感謝大家的閱讀,以上就是“如何分析web前端中的深拷貝和淺拷貝”的全部內(nèi)容了,學會的朋友趕緊操作起來吧。相信億速云小編一定會給大家?guī)砀鼉?yōu)質(zhì)的文章。謝謝大家對億速云網(wǎng)站的支持!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。