javascript
【进阶1-3期】JavaScript深入之内存空间详细图解
本期的主題是調(diào)用堆棧,本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了解本進(jìn)階計(jì)劃,文末點(diǎn)擊查看全部文章。
如果覺得本系列不錯(cuò),歡迎點(diǎn)贊、評(píng)論、轉(zhuǎn)發(fā),您的支持就是我堅(jiān)持的最大動(dòng)力。
堆棧的內(nèi)容和執(zhí)行順序我就不說了,前面兩篇已經(jīng)介紹過了。
但是今天補(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(); 復(fù)制代碼現(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)轫樞虻牟煌⒉挥绊懳覀兊氖褂?#xff0c;我們只需要關(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)存中分別占有固定大小的空間,通過按值來訪問。基本類型一共有6種: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的值是多少? 復(fù)制代碼問題2:
var a = { name: '前端開發(fā)' } var b = a; b.name = '進(jìn)階';// 這時(shí)a.name的值是多少 復(fù)制代碼問題3:
var a = { name: '前端開發(fā)' } var b = a; a = null;// 這時(shí)b的值是多少 復(fù)制代碼現(xiàn)在來解答一下,三個(gè)問題的答案分別是20、‘進(jìn)階’、{ name: '前端開發(fā)' }
- 對(duì)于問題1,a、b都是基本類型,它們的值是存儲(chǔ)在棧中的,a、b分別有各自獨(dú)立的棧空間,所以修改了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 的值是多少 復(fù)制代碼參考
前端基礎(chǔ)進(jìn)階(一):內(nèi)存空間詳細(xì)圖解
解讀 JavaScript 之引擎、運(yùn)行時(shí)和堆棧調(diào)用
JavaScript變量——棧內(nèi)存or堆內(nèi)存
進(jìn)階系列目錄
- 【進(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源碼解析
交流
進(jìn)階系列文章匯總:github.com/yygmind/blo…,內(nèi)有優(yōu)質(zhì)前端資料,覺得不錯(cuò)點(diǎn)個(gè)star。
我是木易楊,網(wǎng)易高級(jí)前端工程師,跟著我每周重點(diǎn)攻克一個(gè)前端面試重難點(diǎn)。接下來讓我?guī)阕哌M(jìn)高級(jí)前端的世界,在進(jìn)階的路上,共勉!
總結(jié)
以上是生活随笔為你收集整理的【进阶1-3期】JavaScript深入之内存空间详细图解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 冲刺第八天 12.4 TUE
- 下一篇: hdfs写并发问题