(關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo))
本周正式開始前端進(jìn)階的第一期,本周的主題是調(diào)用堆棧,今天是第3天。
本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了解本進(jìn)階計(jì)劃,點(diǎn)擊查看前端進(jìn)階的破冰之旅
本期推薦文章
前端基礎(chǔ)進(jìn)階(一):內(nèi)存空間詳細(xì)圖解 ,由于微信不能訪問外鏈,點(diǎn)擊閱讀原文就可以啦。
推薦理由
今天介紹的是JS內(nèi)存空間,了解內(nèi)存空間中的堆和棧原理對(duì)于理解JS閉包、Event Loop等有很大幫助,本文使用圖解形式,即使是第一次接觸本文的讀者也很容易理解堆棧。文末提供了一個(gè)思考題,歡迎加群討論。
閱讀筆記
堆棧的內(nèi)容和執(zhí)行順序我就不說了,前面兩篇已經(jīng)介紹過了。
【進(jìn)階1-1期】理解JavaScript 中的執(zhí)行上下文和執(zhí)行棧
【進(jìn)階1-2期】JavaScript深入之執(zhí)行上下文棧和變量對(duì)象
[圖片上傳失敗...(image-be7894-1543477607420)]
但是今天補(bǔ)充一個(gè)知識(shí)點(diǎn):某些情況下,調(diào)用堆棧中函數(shù)調(diào)用的數(shù)量超出了調(diào)用堆棧的實(shí)際大小,瀏覽器會(huì)拋出一個(gè)錯(cuò)誤終止運(yùn)行。
對(duì)于下面的遞歸就會(huì)無限制的執(zhí)行下去,直到超出調(diào)用堆棧的實(shí)際大小,這個(gè)是瀏覽器定義的。
function foo() {
foo();
}
foo();

現(xiàn)在正式開始今天的主題,內(nèi)存空間詳解
棧數(shù)據(jù)結(jié)構(gòu)
棧的結(jié)構(gòu)就是后進(jìn)先出(LIFO),如果讀過前面兩篇文章應(yīng)該是相當(dāng)熟悉了。文中使用乒乓球盒子的結(jié)構(gòu)來解釋。
處于盒子中最頂層的乒乓球5,它一定是最后被放進(jìn)去,但可以最先被使用。而我們想要使用底層的乒乓球1,就必須將上面的4個(gè)乒乓球取出來,讓乒乓球1處于盒子頂層。

堆數(shù)據(jù)結(jié)構(gòu)
堆數(shù)據(jù)結(jié)構(gòu)是一種樹狀結(jié)構(gòu)。它的存取數(shù)據(jù)的方式與書架和書非常相似。我們只需要知道書的名字就可以直接取出書了,并不需要把上面的書取出來。JSON格式的數(shù)據(jù)中,我們存儲(chǔ)的key-value可以是無序的,因?yàn)轫樞虻牟煌⒉挥绊懳覀兊氖褂?,我們只需要關(guān)心書的名字。
隊(duì)列
隊(duì)列是一種先進(jìn)先出(FIFO)的數(shù)據(jù)結(jié)構(gòu),這是事件循環(huán)(Event Loop)的基礎(chǔ)結(jié)構(gòu),事件循環(huán)我們會(huì)在第8期詳解介紹。

變量的存放
首先我們應(yīng)該知道內(nèi)存中有棧和堆,那么變量應(yīng)該存放在哪里呢,堆?棧?
- 1、基本類型 --> 保存在棧內(nèi)存中,因?yàn)檫@些類型在內(nèi)存中分別占有固定大小的空間,通過按值來訪問?;绢愋鸵还灿?種:Undefined、Null、Boolean、Number 、String和Symbol
- 2、引用類型 --> 保存在堆內(nèi)存中,因?yàn)檫@種值的大小不固定,因此不能把它們保存到棧內(nèi)存中,但內(nèi)存地址大小的固定的,因此保存在堆內(nèi)存中,在棧內(nèi)存中存放的只是該對(duì)象的訪問地址。當(dāng)查詢引用類型的變量時(shí), 先從棧中讀取內(nèi)存地址, 然后再通過地址找到堆中的值。對(duì)于這種,我們把它叫做按引用訪問。
在計(jì)算機(jī)的數(shù)據(jù)結(jié)構(gòu)中,棧比堆的運(yùn)算速度快,Object是一個(gè)復(fù)雜的結(jié)構(gòu)且可以擴(kuò)展:數(shù)組可擴(kuò)充,對(duì)象可添加屬性,都可以增刪改查。將他們放在堆中是為了不影響棧的效率。而是通過引用的方式查找到堆中的實(shí)際對(duì)象再進(jìn)行操作。所以查找引用類型值的時(shí)候先去棧查找再去堆查找。
幾個(gè)問題
問題1:
var a = 20;
var b = a;
b = 30;
// 這時(shí)a的值是多少?
問題2:
var a = { name: '前端開發(fā)' }
var b = a;
b.name = '進(jìn)階';
// 這時(shí)a.name的值是多少
問題3:
var a = { name: '前端開發(fā)' }
var b = a;
a = null;
// 這時(shí)b的值是多少
現(xiàn)在來解答一下,三個(gè)問題的答案分別是20、‘進(jìn)階’、{ name: '前端開發(fā)' }
- 對(duì)于問題1,a、b都是基本類型,它們的值是存儲(chǔ)在棧中的,a、b分別有各自獨(dú)立的??臻g,所以修改了b的值以后,a的值并不會(huì)發(fā)生變化。
- 對(duì)于問題2,a、b都是引用類型,棧內(nèi)存中存放地址指向堆內(nèi)存中的對(duì)象,引用類型的復(fù)制會(huì)為新的變量自動(dòng)分配一個(gè)新的值保存在變量對(duì)象中,但只是引用類型的一個(gè)地址指針而已,實(shí)際指向的是同一個(gè)對(duì)象,所以修改
b.name的值后,相應(yīng)的a.name也就發(fā)生了改變。 - 對(duì)于問題3,首先要說明的是
null是基本類型,a = null之后只是把a(bǔ)存儲(chǔ)在棧內(nèi)存中地址改變成了基本類型null,并不會(huì)影響堆內(nèi)存中的對(duì)象,所以b的值不受影響。
內(nèi)存空間管理
JavaScript的內(nèi)存生命周期是
- 1、分配你所需要的內(nèi)存
- 2、使用分配到的內(nèi)存(讀、寫)
- 3、不需要時(shí)將其釋放、歸還
JavaScript有自動(dòng)垃圾收集機(jī)制,最常用的是通過標(biāo)記清除的算法來找到哪些對(duì)象是不再繼續(xù)使用的,使用a = null其實(shí)僅僅只是做了一個(gè)釋放引用的操作,讓 a 原本對(duì)應(yīng)的值失去引用,脫離執(zhí)行環(huán)境,這個(gè)值會(huì)在下一次垃圾收集器執(zhí)行操作時(shí)被找到并釋放。
在局部作用域中,當(dāng)函數(shù)執(zhí)行完畢,局部變量也就沒有存在的必要了,因此垃圾收集器很容易做出判斷并回收。但是全局變量什么時(shí)候需要自動(dòng)釋放內(nèi)存空間則很難判斷,因此在開發(fā)中,需要盡量避免使用全局變量。
思考題
var a = {n: 1};
var b = a;
a.x = a = {n: 2};
a.x // 這時(shí) a.x 的值是多少
b.x // 這時(shí) b.x 的值是多少
參考
前端基礎(chǔ)進(jìn)階(一):內(nèi)存空間詳細(xì)圖解
往期文章查看
- 【進(jìn)階1-1期】理解JavaScript 中的執(zhí)行上下文和執(zhí)行棧
- 【進(jìn)階1-2期】JavaScript深入之執(zhí)行上下文棧和變量對(duì)象
- 【進(jìn)階1-3期】JavaScript深入之內(nèi)存空間詳細(xì)圖解
- 【進(jìn)階1-4期】JavaScript深入之帶你走進(jìn)內(nèi)存機(jī)制制
- 【進(jìn)階1-5期】JavaScript深入之4類常見內(nèi)存泄漏及如何避免
- 【進(jìn)階2-1期】深入淺出圖解作用域鏈和閉包
每周計(jì)劃安排
每周面試重難點(diǎn)計(jì)劃如下,如有修改會(huì)通知大家。每周一期,為期半年,準(zhǔn)備明年跳槽的小伙伴們可以把本公眾號(hào)置頂了。
- 【進(jìn)階1期】 調(diào)用堆棧
- 【進(jìn)階2期】 作用域閉包
- 【進(jìn)階3期】 this全面解析
- 【進(jìn)階4期】 深淺拷貝原理
- 【進(jìn)階5期】 原型Prototype
- 【進(jìn)階6期】 高階函數(shù)
- 【進(jìn)階7期】 事件機(jī)制
- 【進(jìn)階8期】 Event Loop原理
- 【進(jìn)階9期】 Promise原理
- 【進(jìn)階10期】Async/Await原理
- 【進(jìn)階11期】防抖/節(jié)流原理
- 【進(jìn)階12期】模塊化詳解
- 【進(jìn)階13期】ES6重難點(diǎn)
- 【進(jìn)階14期】計(jì)算機(jī)網(wǎng)絡(luò)概述
- 【進(jìn)階15期】瀏覽器渲染原理
- 【進(jìn)階16期】webpack配置
- 【進(jìn)階17期】webpack原理
- 【進(jìn)階18期】前端監(jiān)控
- 【進(jìn)階19期】跨域和安全
- 【進(jìn)階20期】性能優(yōu)化
- 【進(jìn)階21期】VirtualDom原理
- 【進(jìn)階22期】Diff算法
- 【進(jìn)階23期】MVVM雙向綁定
- 【進(jìn)階24期】Vuex原理
- 【進(jìn)階25期】Redux原理
- 【進(jìn)階26期】路由原理
- 【進(jìn)階27期】VueRouter源碼解析
- 【進(jìn)階28期】ReactRouter源碼解析
交流
本人Github鏈接如下,歡迎各位Star
http://github.com/yygmind/blog
我是木易楊,網(wǎng)易高級(jí)前端工程師,跟著我每周重點(diǎn)攻克一個(gè)前端面試重難點(diǎn)。接下來讓我?guī)阕哌M(jìn)高級(jí)前端的世界,在進(jìn)階的路上,共勉!
如果你想加群討論每期面試知識(shí)點(diǎn),公眾號(hào)回復(fù)[加群]即可
