與之前的切圖比較,如今的前端開發對js的要求彷佛愈來愈高,在開發中,咱們不只僅是要知道如何運用現有的框架(react/vue/ng),javascript
並且咱們對一些基礎的知識的依賴愈來愈大。前端
如今咱們就用平民的方法講解下執行上下文/調用堆棧/內存棧。vue
理解下 javascript 在執行中,javascript 引擎(v8) 對咱們加載的代碼作了寫什麼?java
咱們整一段很是簡單的 js 代碼來分析 v8 引擎和執行上下文/調用堆棧/內存棧的關係。react
<script> var a = 1; function say() { var c = 4 console.log(c)
console.log(a)
var d = 5 } console.log(b)
console.log(a) say() var b = 2; </script>
一、在 v8 引擎加載到這段代碼閉包
二、引擎解析代碼,建立一個 全局執行上下文(調用堆棧/內存棧)框架
三、解析代碼,將全局的全部的變量/聲明函數添加到全局執行上下文的內存棧中。函數
這裏會將 變量 a 和 b / 函數 say 添加到內存棧中。全部的全局的變量和函數都會添加進去對象
開始執行的樣子:blog
4.將全局的執行方法,都 push 到調用堆棧中
調用 console.log(b) 方法,執行到 console.log(b) 這一步的時候,全局執行上下文樣子:
在從開始執行到這裏的過程當中,咱們對一些變量作了賦值 a = 1 , b 併爲賦值,還是 undefined 。
這裏打印的是一個 undefined
這裏就是爲何會出現 變量提高 的緣由
這裏 console.log(b) 執行完成後,會直接 pop 彈出 調用堆棧。
調用 console.log(a) , 在console.log(b) 到 console.log(a) 並未有任何賦值操做。
因此內存棧中未有任何變化。
可是調用堆棧裏面會有變化,在這裏面console.log(b)已經執行完成,會被 pop 推出棧,而後到了console.log(a),試圖樣子:
這裏打印 a 是 1
結束完成以後,console.log(a) 會被彈出棧。
調用 say() 函數,將 say() push 的調用堆棧中。
建立一個新的 say 的執行上下文。
這裏爲 say 從新建立了一個 執行上下文 。而且將它內部的 變量和函數推入它對應的 內存棧 中。
將 c : 4 , d : 5 推到 內存棧中。
解析 say 函數,而且執行內部的 console.log(c) , console.log(a) 。
這裏堆棧一次執行 console.log(c) , console.log(a) .
執行完成以後會被彈出來。
打印 4 , 5 。
當 say () 執行完畢後,回收內存棧已經調用棧。
在理解這些時候,咱們能夠先看下 值類型 和 引用類型,值類型 和 引用類型 的存儲方式來區分前端的堆棧。
值類型/原始類型 : undefined 、null 、number 、string 、boolean
引用類型/堆類型 : object 、function 、array
保存在內存棧中,分配固定的空間,因此保存的值是不可變的。
js 代碼執行的或者某個方法執行的時候,都會有本身獨立的執行上下文,其中包括內存棧和調用棧,該執行上下文中定義的值類型就會保存在該內存棧中。
當該方法執行結束,這個內存棧就會銷燬,值類型也隨之移除
值類型的特色:
一、任何方法都沒法改變值類型的
var name = 'xiao'; name.toUpperCase(); // 輸出 'XIAO' console.log(name); // 輸出 'xiao'
該字符串調用了 toUpperCase() 方法,可是並未改變 name 的值
二、相同類型的值類型的比較是它們值的比較
相同類型的值類型在比較時候,只有它們的值相等,則它們才相等。
三、值類型都存放在內存棧中
上面已經介紹過了。
四、保存的是值自己的值,不是指向的地址。
值保存在堆內存中,佔用的空間也不固定,因此保存的值是能夠變的
當咱們建立一個對象的時候,咱們會將該對象保存在運行的內存堆中,以便與反覆利用。
當被某一個變量引用的時候,會給變量該內存堆中的該對象的地址,而且把該對象的地址保存在內存棧中,而不是該對象的自己
當引用該變量所在的方法或者是執行上下文執行結束的時候,並不會銷燬,只有在沒有被任何引用的時候,該對象纔會被銷燬。
這裏的這種銷燬方法就是垃圾回收中的一種,叫作標記回收
標記回收( 以對象爲例,當這個對象每被引用一次,就在該對象的標記上面 +1 ,當某一個引用該對象的變量不引用了就 -1 ,當
標記爲 0 的時候,被系統檢測到以後,就會銷燬。 )
引用類型的特色:
一、引用類型的值是可變的
var obj = {a:1} obj.b = 2
二、引用類型在內存棧中保存對象地址,在堆內存中保存對象的自己
三、引用類型的比較(===),是比較它們保存的對象的堆內存地址
四、引用類型的賦值,當給某一個變量複製的時候,實際是將該對象的堆內存地址複製給變量
前端的基礎(閉包,原型,做用域),在這裏咱們只要理解了執行上下文,咱們就能夠很好的區分做用域和閉包,
由於它們都至關於一個方法,當它們執行的時候,都會相應的建立本身的執行上下文,而且有本身的內存棧和調用棧。
當它們執行的時候都會對應的運用本身的內存中的變量。
值類型和引用類型的區分,咱們能很快的做出類型的比較。
經過變量的存儲方式來區分每個變量的種類和功能。