?前端開發工程師必讀系列之 Part1.執行上下文

Tim在掘金發表於2018-12-24

寫在前面

首先,這系列文章是來自俄國某大神的部落格。dmitrysoshnikov.com/

其次,其實在網上已經有了此係列的翻譯文章。本人原本只想做個搬運工,So,不要說我抄襲什麼的感謝了!

介紹

這篇文章我們將介紹ECMAScript的執行上下文和與執行上下文相關的可執行程式碼型別。

定義

每當控制器進入一段ECMAScript的可執行程式碼時,控制器就進入了一個執行上下文。標準中並沒有準確定義執行上下文(縮寫為EC(Execution context))的結構和型別,這對ECMAScript執行引擎來說是一個問題。

活動的執行上下文被描述成一個棧,棧底總是全域性上下文,棧頂總是當前(被啟用)的執行上下文。棧的修改(即: 進棧/出棧)發生在進入一個新的執行上下文與退出一個正在執行的執行上下文(有點拗口)。

可執行程式碼的型別

我們抽象出來的關於可執行上下文的概念,其型別與可執行程式碼有關。我們的執行上下文其實就是在說可執行程式碼的型別。

舉個例子,我們把執行上下文的棧抽象成一個陣列:

ECStack = [];
複製程式碼

這個陣列被push是在進入一個新的執行上下文時發生(即使是函式的遞迴或者作為一個建構函式)。

全域性程式碼

這類程式碼是在“程式”級別上被處理的:比如,載入一個外部的js檔案或者內聯的js程式碼(被包含在標籤內)。全域性程式碼不包含任何函式體內的程式碼。

在程式初始化的時候。ECStack變成這樣:

ECStack = [
  globalContext
];
複製程式碼

函式程式碼

在每次執行到函式程式碼時(各種各樣的函式),ECStack就會push進去其函式執行上下文。有必要注意的是:函式內部的程式碼跟這個上下文沒有任何關係。

舉個例子,讓我們看一個函式,其呼叫自己。

(function foo(flag) {
  if (flag) {
    return;
  }
  foo(true);
})(false);
複製程式碼

然後我們可以看到ECStack被修改成這樣:

//外部foo函式被啟用時
ECStack = [
  <foo> functionContext
  globalContext
];
  
//內部foo函式被啟用時
ECStack = [
  <foo> functionContext – recursively 
  <foo> functionContext
  globalContext
];
複製程式碼

函式每次return時或者執行完時,其執行上下文就會退出,ECStack會相應的彈出這個執行上下文,然後很多次的進棧、出棧,最後直到所有可執行程式碼被執行完以後,只剩globalContext。

(eval的部分也很有意思,只不過認為不常用,所以不寫出來)

結論

這篇文章對系列文章中的“變數物件”、“作用域鏈”都很重要,希望可以深入理解掌握。

相關文章