摘要:中有三種數(shù)據(jù)結(jié)構(gòu)棧堆隊(duì)列。前端進(jìn)擊的巨人一執(zhí)行上下文與執(zhí)行棧,變量對(duì)象中解釋執(zhí)行棧時(shí),舉了一個(gè)乒乓球盒子的例子,來(lái)演示棧的存取方式,這里再舉個(gè)栗子搭積木。對(duì)于基本類型,棧中存儲(chǔ)的就是它自身的值,所以新內(nèi)存空間存儲(chǔ)的也是一個(gè)值。
面試經(jīng)常遇到的深淺拷貝,事件輪詢,函數(shù)調(diào)用棧,閉包等容易出錯(cuò)的題目,究其原因,都是跟JavaScript基礎(chǔ)知識(shí)不牢固有關(guān),下層地基沒(méi)打好,上層就是豆腐渣工程,新人小白,踏實(shí)踩土才是關(guān)鍵。
打地基第二篇:本篇我們將對(duì)JavaScript數(shù)據(jù)結(jié)構(gòu)的知識(shí)點(diǎn)詳解一二。
JavaScript中有三種數(shù)據(jù)結(jié)構(gòu): 棧(stack) 、堆(heap)、 隊(duì)列(queue)。
棧(stack)棧的特點(diǎn)是"LIFO,即后進(jìn)先出(Last in, first out)"。數(shù)據(jù)存儲(chǔ)時(shí)只能從頂部逐個(gè)存入,取出時(shí)也需從頂部逐個(gè)取出?!肚岸诉M(jìn)擊的巨人(一):執(zhí)行上下文與執(zhí)行棧,變量對(duì)象》中解釋執(zhí)行棧時(shí),舉了一個(gè)乒乓球盒子的例子,來(lái)演示棧的存取方式,這里再舉個(gè)栗子搭積木。
舉個(gè)栗子:乒乓球盒子/搭建積木
JavaScript中Array數(shù)組模擬棧:
var arr = [1, 2, 3, 4, 5]; arr.push(6); // 存入數(shù)據(jù) arr -> [1, 2, 3, 4, 5, 6] arr.pop(); // 取出數(shù)據(jù) arr -> [1, 2, 3, 4, 5]堆(heap)
堆的特點(diǎn)是"無(wú)序"的key-value"鍵值對(duì)"存儲(chǔ)方式。
舉個(gè)栗子:書(shū)架存書(shū)
我們想要在書(shū)架上找到想要的書(shū),最直接的方式就是通過(guò)查找書(shū)名,書(shū)名就是我們的key。拿著這把key,就可以輕松檢索到對(duì)應(yīng)的書(shū)籍。
"堆的存取方式跟順序沒(méi)有關(guān)系,不局限出入口"。
隊(duì)列 (queue)隊(duì)列的特點(diǎn)是是"FIFO,即先進(jìn)先出(First in, first out)" 。
數(shù)據(jù)存取時(shí)"從隊(duì)尾插入,從隊(duì)頭取出"。
"與棧的區(qū)別:棧的存入取出都在頂部一個(gè)出入口,而隊(duì)列分兩個(gè),一個(gè)出口,一個(gè)入口"。
舉個(gè)栗子:排隊(duì)取餐
JavaScript中Array數(shù)組模擬隊(duì)列:
var arr = [1, 2, 3, 4, 5]; // 隊(duì)尾in arr.push(6); // 存入 arr -> [1, 2, 3, 4, 5, 6] // 隊(duì)頭out arr.shift(); // 取出 arr -> [2, 3, 4, 5, 6]棧、堆、隊(duì)列在JavaScript中的應(yīng)用 1. 代碼運(yùn)行方式(棧應(yīng)用/函數(shù)調(diào)用棧)
《前端進(jìn)擊的巨人(一):執(zhí)行上下文與執(zhí)行棧,變量對(duì)象》詳解了JavaScript運(yùn)行時(shí)的函數(shù)調(diào)用過(guò)程,而其中執(zhí)行棧(函數(shù)調(diào)用棧)就是用到棧的數(shù)據(jù)結(jié)構(gòu)。
JavaScript中函數(shù)的執(zhí)行過(guò)程,其實(shí)就是一個(gè)入棧出棧的過(guò)程:
當(dāng)腳本要調(diào)用一個(gè)函數(shù)時(shí),JS解析器把該函數(shù)推入棧中(push)并執(zhí)行
當(dāng)函數(shù)運(yùn)行結(jié)束后,JS解析器將它從堆棧中推出(pop)
具體執(zhí)行過(guò)程可翻閱上篇文章《前端進(jìn)擊的巨人(一):執(zhí)行上下文與執(zhí)行棧,變量對(duì)象》,這里不再贅述。
2. 內(nèi)存存儲(chǔ)(棧、堆)JavaScript中變量類型有兩種:
基礎(chǔ)類型(Undefined, Null, Boolean, Number, String, Symbol)一共6種
引用類型(Object)
基礎(chǔ)類型的值保存在棧中,這些類型的值有固定大小,"按值來(lái)訪問(wèn)";
引用類型的值保存在堆中,棧中存儲(chǔ)的是引用類型的引用地址(地址指針),"按引用訪問(wèn)",引用類型的值沒(méi)有固定大小,可擴(kuò)展(一個(gè)對(duì)象我們可以添加多個(gè)屬性)。
3. 事件輪詢(隊(duì)列)JavaScript中事件輪詢(Event Loop)的執(zhí)行機(jī)制,就是采用隊(duì)列的存取方式,因事件輪詢(Event Loop)也是JS基礎(chǔ)中的一個(gè)比較難理解的知識(shí)點(diǎn),后續(xù)另開(kāi)一篇章再作詳細(xì)探究。
深淺拷貝將一個(gè)變量的值賦值給另一個(gè)變量,相當(dāng)于在棧內(nèi)存中創(chuàng)建了一個(gè)新的內(nèi)存空間,然后從棧中復(fù)制值,存儲(chǔ)到這個(gè)新空間中。對(duì)于基本類型,棧中存儲(chǔ)的就是它自身的值,所以新內(nèi)存空間存儲(chǔ)的也是一個(gè)值。直接改變新變量的值,不會(huì)影響到舊變量的值,因?yàn)樗麄冎荡鎯?chǔ)的內(nèi)存空間不同。
// 基本類型復(fù)制變量 var a = 10; var b = a; b = 20; a // 10 b // 20
而對(duì)于引用類型來(lái)說(shuō),同樣是復(fù)制棧中存儲(chǔ)的值。但是棧存儲(chǔ)的只是其引用地址,其具體的值存儲(chǔ)在堆中。變量復(fù)制僅復(fù)制棧中存儲(chǔ)的值,不會(huì)復(fù)制堆中存儲(chǔ)的值,所以新變量在棧中的值是一個(gè)地址指針。
// 引用類型復(fù)制變量 var a = { age: 27 }; var b = a; b.age = 29; a.age == b.age; // 29
可見(jiàn),變量復(fù)制賦值,都屬于棧存儲(chǔ)拷貝,因此深淺拷貝可以這樣區(qū)分:
"淺拷貝:棧存儲(chǔ)拷貝"
"深拷貝:棧堆存儲(chǔ)拷貝"
深拷貝會(huì)同時(shí)開(kāi)辟新的棧內(nèi)存,堆內(nèi)存空間。
// 利用JSON對(duì)象方法實(shí)現(xiàn)深拷貝 var a = { age: 27 }; var b = JSON.parse(JSON.stringify(a)); b.age = 29; a.age // 27 b.age // 29函數(shù)傳參數(shù)是按值傳遞?按引用傳遞?
var person = { age: 27 }; function foo (person) { person.age = 29; } foo(person); person.age // 29;
函數(shù)調(diào)用時(shí),會(huì)對(duì)參數(shù)賦值。而參數(shù)傳遞過(guò)程其實(shí)同樣是變量復(fù)制的過(guò)程,所以它是按值傳遞。var person = person,因?yàn)閭鬟f參數(shù)是對(duì)象時(shí),變量復(fù)制僅復(fù)制的棧存儲(chǔ)(淺拷貝),所以修改對(duì)象屬性會(huì)造成外部變量對(duì)象的修改。
至此,當(dāng)我們理清棧、堆數(shù)據(jù)結(jié)構(gòu),以及JS中數(shù)據(jù)類型存取方式。深淺拷貝問(wèn)題也就通順了。
內(nèi)存空間管理JavaScript執(zhí)行過(guò)程中內(nèi)存分配:
為變量對(duì)象分配需要的內(nèi)存
在分配到的內(nèi)存中進(jìn)行讀/寫(xiě)操作
不再使用時(shí)將其銷毀,釋放內(nèi)存
內(nèi)存管理不善,會(huì)出現(xiàn)內(nèi)存泄露,造成瀏覽器內(nèi)存占用過(guò)多,頁(yè)面卡頓等問(wèn)題。(后續(xù)性能優(yōu)化篇章續(xù)講)
垃圾回收機(jī)制JavaScript中有自動(dòng)垃圾回收機(jī)制,會(huì)通過(guò)標(biāo)記清除的算法識(shí)別哪些變量對(duì)象不再使用,對(duì)其進(jìn)行銷毀。開(kāi)發(fā)者也可在代碼中手動(dòng)設(shè)置變量值為null(a = null)進(jìn)行標(biāo)記清除,讓其失去引用,以便下一次垃圾回收時(shí)進(jìn)行有效回收。
局部環(huán)境中,函數(shù)執(zhí)行完成后,函數(shù)局部環(huán)境聲明的變量不再需要時(shí),就會(huì)被垃圾回收銷毀(理想的情況下,閉包會(huì)阻止這一過(guò)程)。
全局環(huán)境只有頁(yè)面退出時(shí)才會(huì)出棧,解除變量引用。所以開(kāi)發(fā)者應(yīng)盡量避免在全局環(huán)境中創(chuàng)建全局變量,如需使用,也要在不需要時(shí)手動(dòng)標(biāo)記清除,將其內(nèi)存釋放掉。
垃圾回收算法除了"標(biāo)記清除",還有一種"引用計(jì)數(shù)",不常用,僅作了解。
參考文檔:
stack的三種含義
內(nèi)存空間詳細(xì)圖解
JavaScript變量——棧內(nèi)存or堆內(nèi)存
本文首發(fā)Github,期待Star!
https://github.com/ZengLingYong/blog
作者:以樂(lè)之名
本文原創(chuàng),有不當(dāng)?shù)牡胤綒g迎指出。轉(zhuǎn)載請(qǐng)指明出處。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/101048.html
摘要:的垃圾回收器,進(jìn)行回收。它們的數(shù)據(jù)就存放在堆內(nèi)存中,大小不一定,動(dòng)態(tài)分配內(nèi)存,可隨時(shí)修改。引用類型的變量存的是其在堆內(nèi)存中的地址,值的讀取,就是讀取這個(gè)內(nèi)存地址中儲(chǔ)存的內(nèi)容。 這東西還是很重要的,你要是搞懂了,就會(huì)去除很多困惑,比如不知道大家在學(xué)習(xí)js 的時(shí)候,有沒(méi)有對(duì) 基礎(chǔ)類型 和 引用類型 感到困惑過(guò),兩者之間 表現(xiàn)的不同之處。 js 不同其他編程語(yǔ)言,它是腳本語(yǔ)言。所以,它的數(shù)...
摘要:在中,通過(guò)棧的存取方式來(lái)管理執(zhí)行上下文,我們可稱其為執(zhí)行棧,或函數(shù)調(diào)用棧。而處于棧頂?shù)氖钱?dāng)前正在執(zhí)行函數(shù)的執(zhí)行上下文,當(dāng)函數(shù)調(diào)用完成后,它就會(huì)從棧頂被推出理想的情況下,閉包會(huì)阻止該操作,閉包后續(xù)文章深入詳解。 寫(xiě)在開(kāi)篇 已經(jīng)不敢自稱前端小白,曾經(jīng)吹過(guò)的牛逼總要一點(diǎn)點(diǎn)去實(shí)現(xiàn)。 正如前領(lǐng)導(dǎo)說(shuō)的,自己喝酒吹過(guò)的牛皮,跪著都得含著淚去實(shí)現(xiàn)。 那么沒(méi)有年終完美總結(jié),來(lái)個(gè)新年莽撞開(kāi)始可好。 進(jìn)擊巨...
摘要:進(jìn)擊的巨人第三篇,本篇就作用域作用域鏈閉包等知識(shí)點(diǎn),一一擊破。在此我們遵照的方式,暫且稱是閉包。所以,一名合格的前端,除了會(huì)用閉包,還要正確的解除閉包引用。 進(jìn)擊的巨人第三篇,本篇就作用域、作用域鏈、閉包等知識(shí)點(diǎn),一一擊破。 showImg(https://segmentfault.com/img/bVburWd?w=1280&h=854); 作用域 作用域:負(fù)責(zé)收集并維護(hù)由所有聲明的...
摘要:有關(guān)函數(shù)柯里化的詳解,請(qǐng)回閱前端進(jìn)擊的巨人五學(xué)會(huì)函數(shù)柯里化。構(gòu)造函數(shù)中的通過(guò)操作符可以實(shí)現(xiàn)對(duì)函數(shù)的構(gòu)造調(diào)用。在了解構(gòu)造函數(shù)中的前,有必要先了解下實(shí)例化對(duì)象的過(guò)程。 showImg(https://segmentfault.com/img/bVburMp?w=800&h=600); 常見(jiàn)this的誤解 指向函數(shù)自身(源于this英文意思的誤解) 指向函數(shù)的詞法作用域(部分情況) th...
摘要:隆重請(qǐng)出主角防抖與節(jié)流。防抖與節(jié)流的異同相同都是防止某一時(shí)間段內(nèi),函數(shù)被頻繁調(diào)用執(zhí)行,通過(guò)時(shí)間頻率控制,減少回調(diào)函數(shù)執(zhí)行次數(shù),來(lái)實(shí)現(xiàn)相關(guān)性能優(yōu)化。參考文章分鐘理解的節(jié)流防抖及使用場(chǎng)景函數(shù)防抖和節(jié)流 showImg(https://segmentfault.com/img/bVburM8?w=800&h=600); 本篇課題,或許早已是爛大街的解讀文章。不過(guò)春招系列面試下來(lái),不少伙伴們還...
閱讀 2449·2023-04-25 14:17
閱讀 1611·2021-11-23 10:02
閱讀 2251·2021-11-23 09:51
閱讀 960·2021-10-14 09:49
閱讀 3471·2021-10-11 10:57
閱讀 3001·2021-09-24 09:47
閱讀 3131·2021-08-24 10:00
閱讀 2384·2019-08-29 18:46