如果要問到 j**ascript **執行順序的話,想必寫過 j**ascript 的開發者都會有個直觀的印象,那就是順序執行,畢竟:
var foo = function ()foo(); // foo1
var foo = function ()
foo(); // foo2
然而去看這段**:
function foo()foo(); // foo2
function foo()
foo(); // foo2
列印的結果卻是兩個foo2
。
刷過面試題的都知道這是因為 j**ascript 引擎並非一行一行地分析和執行程式,而是一段一段地分析執行。當執行一段**的時候,會進行乙個「準備工作」,比如第乙個例子中的變數提公升,和第二個例子中的函式提公升。
到底j**ascript引擎遇到一段怎樣的**時才會做「準備工作」呢?
這就要說到 j**ascript 的可執行**(executable code)的型別有哪些了?
其實很簡單,就三種,全域性**、函式**、eval**。
舉個例子,當執行到乙個函式的時候,就會進行準備工作,這裡的「準備工作」,讓我們用個更專業一點的說法,就叫做"執行上下文(execution context)"。
接下來問題來了,我們寫的函式多了去了,如何管理建立的那麼多執行上下文呢?
所以 j**ascript 引擎建立了執行上下文棧(execution context stack,ecs)來管理執行上下文
為了模擬執行上下文棧的行為,讓我們定義執行上下文棧是乙個陣列:
ecstack = ;
試想當 j**ascript 開始要解釋執行**的時候,最先遇到的就是全域性**,所以初始化的時候首先就會向執行上下文棧壓入乙個全域性執行上下文,我們用 globalcontext 表示它,並且只有當整個應用程式結束的時候,ecstack 才會被清空,所以 ecstack 最底部永遠有個 globalcontext:
ecstack = [globalcontext
];
現在 j**ascript 遇到下面的這段**了:
function fun3()function fun2()
function fun1()
fun1();
當執行乙個函式的時候,就會建立乙個執行上下文,並且壓入執行上下文棧,當函式執行完畢的時候,就會將函式的執行上下文從棧中彈出。知道了這樣的工作原理,讓我們來看看如何處理上面這段**:
// 偽**// fun1()
ecstack.push(> functioncontext);
// fun1中竟然呼叫了fun2,還要建立fun2的執行上下文
ecstack.push(> functioncontext);
// 擦,fun2還呼叫了fun3!
ecstack.push(> functioncontext);
// fun3執行完畢
ecstack.pop();
// fun2執行完畢
ecstack.pop();
// fun1執行完畢
ecstack.pop();
// j**ascript接著執行下面的**,但是ecstack底層永遠有個globalcontext
好啦,現在我們已經了解了執行上下文棧是如何處理執行上下文的,所以讓我們看看上篇文章《j**ascript深入之詞法作用域和動態作用域》最後的問題:
var scope = "global scope";function checkscope()
return f();
}checkscope();
var scope = "global scope";function checkscope()
return f;
}checkscope()();
兩段**執行的結果一樣,但是兩段**究竟有哪些不同呢?
答案就是執行上下文棧的變化不一樣。
讓我們模擬第一段**:
ecstack.push(> functioncontext);ecstack.push(> functioncontext);
ecstack.pop();
ecstack.pop();
讓我們模擬第二段**:
ecstack.push(> functioncontext);ecstack.pop();
ecstack.push(> functioncontext);
ecstack.pop();
是不是有些不同呢?
提公升 執行上下文和執行上下文棧
提公升 1.變數宣告提公升 通過var定義 宣告 的變數,在之前就可以直接使用,但不會被賦值 值 undefined 2.函式宣告提公升 通過function宣告的函式,在之前就可以直接呼叫 函式表示式不能在定義前呼叫 值 函式定義 物件 3.問題 變數提公升和函式提公升怎麼產生的?變數提公升簡單理...
js執行上下文與執行上下文棧
在了解js的執行上下文物件與執行上下文棧之前,我們要先了解兩個概念 即變數提公升跟函式提公升 變數提公升 通過var定義的變數,在定義語句之前我們就可以直接訪問到,不過它的值是undefined 函式提公升 通過function定義的函式,在函式定義語句前,我們就可以直接呼叫 變數提公升與函式提公升...
上下文 上下文棧
全域性 函式 區域性 在執行全域性 前將window確定為全域性執行上下文 對全域性資料進行預處理 var定義的全域性變數 undefined,新增為window的屬性 function宣告的全域性函式 賦值 fun 新增為window的方法 this 賦值 window 開始執行全域性 在呼叫函式...