JavaScript 之執行上下文

本文共 1090 字,讀完只需 4 分鐘javascript

概述

JavaScript 是函數式編程語言,做用域也是以函數爲單位,那麼,這些函數代碼塊是怎麼樣的順序進行的呢, JS 的可執行代碼又分爲 3 種,不一樣類型的代碼有不同的執行環境。本文就梳理有關 JS 執行上下文(execution context),也叫執行環境的知識。java

活動的執行代碼的上下文在語言底層邏輯上構成一個執行上下文棧(excution context stack),咱們知道,棧有兩個行爲,壓入棧和彈出棧,而且有後進先出的特色, 最早進入的項會在棧底最後彈出。git

不一樣執行環境的有其相應的變量對象(Variable Object),某個執行環境的全部可執行代碼都執行完畢後,該環境中的變量對象和函數定義會被清除。github

函數代碼會在執行完後清除變量佔用的內存,全局代碼則會在關閉環境,好比關閉瀏覽器後清除。web

1、代碼類型

JS 中可執行的代碼可分爲三種類型:編程

  1. 全局代碼
  2. 函數代碼
  3. Eval 代碼

全局代碼瀏覽器

在 web 瀏覽器中,全局執行環境是 window 對象,全部的全局變量和函數都是做爲 window 的屬性和方法存在。bash

全局代碼的執行上下文棧能夠表示爲:閉包

ECStack = [
    globalContext
]
複製代碼

函數代碼app

當執行函數代碼時,函數代碼上下文被壓入到執行上下文棧中。函數代碼的執行環境中,有本身的內部的定義的變量和聲明。

function foo1() {
    var name1 = "a";
    console.log(name1)
}

function foo2(){
    var name2 = "b";
    console.log(name2)
}

foo1();
foo2();
複製代碼

上面的執行上下文能夠表示爲:

ECStack = [
    globalContext
];

ECStack.push(<foo1> functionContext);
ECStack.pop();
ECStack.push(<foo2> functionContext);
ECStack.pop();
複製代碼

一個函數,可能有多個執行上下文,每一個函數的調用都會產生新的上下文。

function foo() {
    ...
}

foo("a");
foo("b");
foo("c");
複製代碼

eval 代碼

eval 關鍵字接受一個字符串做爲參數,並將其做爲書寫文字上下文的代碼。

function foo(str, a) {
    eval( str );  // 聲明一個新變量
    console.log(a, b);
}
var b = 123;

foo("var b = 456 ", 123) // 123, 456
複製代碼

以上代碼引用《你不知道的 JavaScript》的例子,eval 函數中的字符串,被當作可執行代碼,最後在 foo 函數中聲明瞭 b 變量,並覆蓋了 foo 函數外部的 b 變量。

eval 函數和 JS 的詞法做用域的行爲,會形成變量環境和執行上下文的混亂,儘可能別使用它。

2、執行上下文棧

前面其實已經提到不少關於執行上下文棧的內容,簡而言之,JS 在遇到全局代碼,函數代碼,eval 代碼時,會建立相應的執行上下文,不一樣的上下文,有其變量對象(variable object: VO)和做用域。

看這一段代碼:

function func3() {
    console.log('fun3')
}

function func2() {
    func3();
}

function func1() {
    func2();
}

func1();
複製代碼

以上代碼引用自冴羽的github,代碼順序用執行上下文棧來表示就是:

ECStack.push(globalContext);

// 調用 func1(), 進入 func1 執行環境
ECStack.push(<func1> functionContext);

// func1中調用了 func2,進入 func2 的執行上下文
ECStack.push(<func2> functionContext);

// func2 調用 func3, 進入 func3 的執行上下文
ECStack.push(<func3> functionContext);

// func3 執行完畢,退出 func3 執行環境
ECStack.pop();

// func2 執行完畢,退出 func2 執行環境
ECStack.pop();

// func1 執行完畢,退出 func1 執行環境
ECStack.pop();
複製代碼

函數代碼執行完畢後,執行上下文棧底只剩下全局代碼上下文 globalContext, 直到關閉瀏覽器纔會完全清空執行上下文棧。

總結

代碼在執行時會建立由不一樣做用域構成的做用域鏈做用域鏈保證 JS 中的變量和函數都可以有序地訪問和執行。

若是是函數代碼,則將其 活動對象 做爲變量對象,活動對象最開始時只包含一個對象,即 arguments 對象。

後面的文章會介紹變量對象(VO)和做用域鏈的具體內容,敬請期待吧。

博客內容源自我的公衆號,專一分享原創文章,歡迎關注。

掘金專欄 JavaScript 系列文章

  1. JavaScript之變量及做用域
  2. JavaScript之聲明提高
  3. JavaScript之執行上下文
  4. JavaScript之變量對象
  5. JavaScript原型與原型鏈
  6. JavaScript之做用域鏈
  7. JavaScript之閉包
  8. JavaScript之this
  9. JavaScript之arguments
  10. JavaScript之按值傳遞
  11. JavaScript之例題中完全理解this
  12. JavaScript專題之模擬實現call和apply
相關文章
相關標籤/搜索