關於javascript中的從堆棧內存到執行上下文

關於javascript中的從堆棧內存到執行上下文

我GitHub上的菜鳥倉庫地址: 點擊跳轉查看其餘相關文章
文章在個人博客上的地址: 點擊跳轉

        先從計算機角度說一下內存:內存,包括三個部分:只讀存儲器(ROM)、隨機存儲器(RAM)和高速緩衝存儲器(Cache)。javascript

        而其中,高速緩衝存儲器(Cache)又分爲三種:一級緩存(L1 Cache)、二級緩存(L2 Cache)、三級緩存(L3 Cache)。java

        當CPU須要數據的時候,就會先找緩存,由於緩存最快,緩存找不到,纔去找慢一點的內存,而後找到後繼續將數據放入緩存,下次還要的時候,仍是先找緩存。git

        簡單來講,緩存中的數據只是內存的一部分,可是讀寫速度最快,因此CPU先找它。github

        扯遠了,回過頭來。算法

        再解釋一下常說的「堆內存」、「棧內存」,「棧內存」也叫作「堆棧內存」,不是兩個一塊兒的總稱,實際上就是棧內存,因此我這裏就分別說「堆內存」和「棧內存」。緩存

        這裏面就有「堆」和「棧」兩個概念了。網絡

        先說說棧,它是放在是在於一級緩存中的,數據被調用的時候放入存儲空間中,而後被調用完成時候,就會被馬上釋放。函數

        再說堆,它是放在二級緩存中的,它的生命週期由虛擬機的垃圾回收算法來決定。因此調用這些對象的速度要相對來得低一些。this

        舉個很簡單的例子來解釋「堆」和「棧」這兩個概念:spa

        棧,有點像漢諾塔那樣的套圈圈,一圈一圈地放上去,前面放的都被壓在了底部,後面的就壓在上面,一層一層疊羅漢,可是取出來的時候,就是後面放上去的先取出來,越早放進去的越後取出來,簡單來講,就是遲來先上岸。

        堆,就像是一堆東西那些,就好像你雜亂的房間,一堆雜物,你想找東西,翻來翻去,找到了,能夠拿走,有些東西,你不拿走,放在那裏,其實就是垃圾。

        通常來講,javascript中的數據類型分爲基本數據類型和引用數據類型,而基本數據類型中的變量名和變量直接存放在棧內存中,而引用數據類型的變量值其實是存放的一個地址指針,因此它的變量名和變量值也是存放在棧內存中,而地址指向的實際內容,則是存放在堆內存中。

        好了,開始說一下執行上下文了。

        有些人會混淆執行上下文和做用域的概念,後面的文章我會說到做用域和做用域鏈,如今先說執行上下文。

        從執行上下文的生命週期來講,包括三個部分:

        一、建立階段;二、執行階段;三、執行完畢階段。

        1、建立階段

        執行上下文是在函數被調用的時候才建立,主要有三個內容:

        一、建立變量對象;二、初始化做用域鏈;三、肯定this的指向。

        2、執行階段

        發生在函數代碼執行階段,主要有三個內容:

        一、變量賦值;二、函數引用;三、執行其餘代碼。

        3、執行完畢階段

        主要內容:執行完畢後跳出執行上下文棧,等待被回收。

        關於建立階段和執行階段的具體內容,可能你們會有疑惑,裏面的具體內容後面文章會慢慢細說。這裏單純說說執行上下文棧。

        舉個簡單例子,函數裏面也會有嵌套函數的狀況,就像這樣:

//函數father
function father(age){
    var me = age + 20;
    //函數son
    function son(age){
        return age;
    }
    return son(me);
}
father(33);

        既然執行上下文是函數被調用的時候建立的,那麼上面這個father函數被調用以後,而後son也被調用了,那它們的執行上下文是什麼關係呢?

        在這裏,Javascript會利用執行上下文棧(Execution context stack,ECS)來管理執行上下文。

        回想一下前面棧內存的概念就很容易理解。

        當調用某個函數的時候,就會建立執行上下文,並壓入執行上下文棧中,當執行完畢的時候,就會從執行上下文棧中跳出,等待被回收。像上面這種函數內嵌套函數的情形,調用father函數的時候,father建立的執行上下文壓入棧中,而後開始執行father的函數體內代碼,由於father函數還沒執行完畢,因此調用son函數時候會將son建立的執行上下文壓入棧中,當son執行完畢,就會跳出,而後father執行完畢,繼續跳出。這就完成了整個father的執行上下文週期。

        仍是那句,遲來先上岸的感受。就好像下面的圖這樣(圖片引用自網絡),下面就是一個執行上下文棧,最底層確定是全局了,而後只要函數沒執行完畢繼續在函數內調用其它函數的話,其它函數的執行上下文就會接着壓上去,最後執行完畢,壓在最上面的上下文先清出,而後其它執行上下文又變成最上面的了,而後執行完畢,繼續清出,就和圖那樣了。

        實際狀況可能不是圖的那樣簡單,可能清出到EC2那一層的時候,還沒執行完這個函數,又調用其它函數,其它的執行上下文又接着壓上去了。

        固然,道理都是同樣的。
es1.gif

相關文章
相關標籤/搜索