一次關於執行上下文的深入了解

2022-09-08 05:00:10 字數 4339 閱讀 6223

最近在刷 冴羽 大大的j**ascript深入系列文章 很良心的文章,再看到第8章j**ascript深入之執行上下文的時候

發現乙個很有趣的題目。

這裡做個筆記。把之前的內容串起來。。畢竟看文章不如自己寫一遍心得,好記性不如爛筆頭。。。

以下的內容很多參考了 冴羽 大大的j**ascript深入系列文章 以及

九死蠶傳人bo的前端基礎高階目錄

兩端**看似結果一樣,但是內在的執行上下文棧缺不一樣。 這裡盡量還原一下為啥是這種結果,個人心得。推薦小夥伴們直接去看原鏈結。

首先js中j**ascript的執行上下文沿用了棧結構,即我們經常說的執行上下文棧,棧是乙個什麼樣的資料結構呢。簡單說就是:先進後出,後進後出。就像高中時化學實驗的量筒,假設往量筒中放入桌球的模型一樣

一號球是最開始放進去的,5好球是最後放入的。但是如果要把所有球拿出來,那麼就是5號球先拿出來,一號球最後。執行上下文棧就是這種結構。

堆的結構類似於圖書館的藏書架子一樣,書本整齊的放在書架上,你只需要知道相對應的書架行號和列號,那麼就可以直接拿到這本書,類似於物件的資料格式一樣 。

js中的變數都以堆的形式放在記憶體中

var obj =  //假設我要拿到cat這個值,我只要知道name這個引數 直接使用obj.name就可以拿到
佇列的機構類似於人的消化系統一樣。。先吃進去的東西先消化,後出的東西必須等前面吃的消化完了之後才能消化。總結就是:先進先出,後進後出。 js中事件的迴圈機制依託於佇列結構。竟然知道了執行上下文是以棧的結構存在的,那麼執行上下文到底是啥。

我們都知道js引擎是按順序一行一行的去編譯**的,每當js引擎遇到可執行**的時候就會建立乙個執行上下文,可以理解為當前**執行所處的環境。而這個可執行**的環境分為三種

全域性環境:j**ascript**執行起來會首先進入該環境(script標籤)

函式環境:當函式被呼叫執行時,會進入當前函式中執行**( fn() )

eval(不建議使用,可忽略)

這裡注意一點。。。是函式呼叫的時候才會建立乙個執行上下文 函式宣告的時候並不會 

當建立乙個執行上下文的時候又會分兩個步驟 1:建立階段 2執行階段

建立階段幹了三件事

其中變數物件的建立又幹了三件事情 。。。為啥這麼多事情 懵逼中

建立arguments物件。檢查當前上下文中的引數,建立該物件下的屬性與屬性值。

檢查當前上下文的函式宣告,也就是使用function關鍵字宣告的函式。在變數物件中以函式名建立乙個屬性,屬性值為指向該函式所在記憶體位址的引用。如果函式名的屬性已經存在,那麼該屬性將會被新的引用所覆蓋。

檢查當前上下文中的變數宣告,每找到乙個變數宣告,就在變數物件中以變數名建立乙個屬性,屬性值為undefined。如果該變數名的屬性已經存在,為了防止同名的函式被修改為undefined,則會直接跳過,原屬性值不會被修改。

總結:函式宣告優先於變數宣告,函式宣告會覆蓋前面的宣告,變數宣告如果前面已經宣告過了就跳過不會覆蓋  (這裡涉及到了宣告提公升的面試問題啦。。。)

舉個栗子:

執行流程是這樣滴

皮拉巴拉建立完之後就進入到了執行階段,當可執行**全部執行完成當前執行上下文出棧,也就是說當函式內的**執行完畢之後它就出棧釋放了。ok 看一下最開始放的兩端**的執行上下文棧結構

第一部分

1

var scope = "global scope";

2function

checkscope()

7return f(); //

相當於 var _content = f() ; return _content 就是先執行f() 然後把f()執行後返回的scope 再一次返回出去8}

9checkscope();

1011

//執行上下文棧的情況

12/*

ecstack 棧結構

13* 1首先全域性執行上下文global context 入棧在棧底 ---ecstack = [global context]

14* 2執行到底16行 checkscope函式呼叫執行 checkscope context 入棧 ---ecstack = [global context , checkscope context]

15* 3這時候進入第13行checkscope函式內部執行 遇到第17行 f()函式呼叫 f context入棧 --- ecstack = [global context,checkscope context, f context]

16* 4進入f函式內部 執行到第16行 f函式可執行**完成全部執行完畢出棧 --- ecstack = [global context,checkscope context]

17* 5這時候重新返回checkscope函式第18行 返回f函式執行完返回的scope checkscope可執行**完成全部執行完畢出棧 --- ecstack = [global context]

18* 6ok 這時候只剩下全域性上下文。。 全域性上下文只有在網頁關閉的時候才出棧19*

20*/

第二部分

var scope = "global scope";

function

checkscope()

returnf;}

checkscope()();

//相當於 var _test = checkscope() ;

//_test()

//執行上下文棧的情況

/*ecstack 棧結構

* 1首先全域性執行上下文global context 入棧在棧底 ---ecstack = [global context]

** 2執行到底9行 checkscope函式呼叫執行 checkscope context 入棧 ---ecstack = [global context , checkscope context]

** --------------------這裡都與前面的第一段**一樣 ------------------------------------

** 3這時候進入第9行checkscope函式內部執行 執行到第7行全部**執行完畢了 checkscope context出棧 ---ecstack = [global context] 。 但是因為返回了乙個f函式的引用 雖*然出棧了,但是垃圾**機制因為函式f的引用還在被占用(下面f函式會被呼叫) 沒法進行**形成閉包(相當於第九行的注釋 )

** 4 第九行第二個括號相當於第十行 f函式進行呼叫 f context 入棧 --- ecstack = [global context,f context] 。注意這裡和上面第一部分**的區別 checkscope已經出棧了

** 5 f函式可執行**完成全部執行完畢出棧 --- ecstack = [global context]

** 6 ok 這時候只剩下全域性上下文。。 全域性上下文只有在網頁關閉的時候才出棧**/

這時候就回答了這個問題啦 第二部分的**checkscope確實是出棧了 只是因為形成了閉包 返回了乙個f函式的引用 垃圾**機制無法進行**  好咯 吃飯去咯

深入 執行上下文

在 深入 詞法作用域與動態作用域 中,提出這樣一道思考題 var scope global scope function checkscope return f checkscope var scope global scope function checkscope return f checks...

JS的執行上下文

執行上下文時是 執行時的環境,js 在執行前進行編譯,那麼會生成兩部分,一部分是可執行的 而另一部分則是執行上下文。用於跟蹤 執行的運 況。執行步驟如下 全域性執行上下文 函式執行上下文和 eval 執行上下文 執行上下文所包含的內容是在不斷的變化的。它主要分為了三個不同的階段。分別是es3階段,e...

js的執行上下文

執行上下文 執行上下文物件就是this 執行上下文 execute context ec 理解 執行的環境 時機 正式執行之前會進入到執行環境 作用域是在 定義的時候產生的,而執行上下文是在 執行的時候產生的。工作 1.建立變數物件 變數函式及函式的引數 全域性 window 區域性 抽象但是確實存...