Js 執行上下文和作用域


1.執行上下文和執行棧

執行上下文就是當前 JavaScript 代碼被解析和執行時所在環境的抽象概念, JavaScript 中運行任何的代碼都是在執行上下文中運行。

執行上下文的生命周期包括三個階段:創建階段→執行階段→回收階段,我們重點介紹創建階段。

創建階段(當函數被調用,但未執行任何其內部代碼之前)會做以下三件事:

  • 創建變量對象:首先初始化函數的參數arguments,提升函數聲明和變量聲明。

  • 創建作用域鏈

  • 確定this指向

function test(arg){
// 1. 形參 arg 是 "hi"
// 2. 因為函數聲明比變量聲明優先級高,所以此時 arg 是 function
console.log(arg);
var arg = 'hello'; // 3.var arg 變量聲明被忽略, arg = 'hello'被執行
function arg(){
  console.log('hello world')
}
console.log(arg);
}
test('hi');
/* 輸出:
function arg() {
  console.log('hello world');
}
hello
*/

 

這是因為當函數執行的時候,首先會形成一個新的私有的作用域,然后依次按照如下的步驟執行:

  • 如果有形參,先給形參賦值

  • 進行私有作用域中的預解釋,函數聲明優先級比變量聲明高,最后后者會被前者所覆蓋,但是可以重新賦值

  • 私有作用域中的代碼從上到下執行

 

函數多了,就有多個函數執行上下文,每次調用函數創建一個新的執行上下文,那如何管理創建的那么多執行上下文呢?

JavaScript 引擎創建了執行棧來管理執行上下文。可以把執行棧認為是一個存儲函數調用的棧結構,遵循先進后出的原則

//引用 慕課手記 的圖示來示例一下:
console.log(1); function pFn() { console.log(2); (function cFn() { console.log(3); }()); console.log(4); } pFn(); console.log(5); //輸出:1 2 3 4 5

從上面的流程圖,我們需要記住幾個關鍵點:

  • JavaScript執行在單線程上,所有的代碼都是排隊執行。

  • 一開始瀏覽器執行全局的代碼時,首先創建全局的執行上下文,壓入執行棧的頂部。

  • 每當進入一個函數的執行就會創建函數的執行上下文,並且把它壓入執行棧的頂部。當前函數執行完成后,當前函數的執行上下文出棧,並等待垃圾回收。

  • 瀏覽器的JS執行引擎總是訪問棧頂的執行上下文。

  • 全局上下文只有唯一的一個,它在瀏覽器關閉時出棧。

 

2.作用域與作用域鏈

ES6 到來JavaScript 有全局作用域、函數作用域和塊級作用域(ES6新增)。

我們可以這樣理解:作用域就是一個獨立的地盤,讓變量不會外泄、暴露出去。也就是說作用域最大的用處就是隔離變量,不同作用域下同名變量不會有沖突

 

函數作用域:顧名思義就是在這個函數體里邊才能訪問的變量;當然可以利用閉包來實現跨區域訪問局部作用域的變量;查看

塊級作用域:ES6新增,用let命令新增了塊級作用域,外層作用域無法獲取到內層作用域,非常安全明了。即使外層和內層都使用相同變量名,也都互不干擾;

接下來我們再來了解下自由變量(也就是全局變量);

 

如下代碼中,console.log(a) 要得到a變量,但是在當前的作用域中沒有定義a(可對比一下b)。當前作用域沒有定義的變量,這成為 自由變量。

var a = 100
function fn() {
  var b = 200
  console.log(a) // 這里的a在這里就是一個自由變量  100
  console.log(b) // 200
}
fn()

 

接下來再看一個示例:

function F1() {
  var a = 100
  return function () {
    console.log(a)
  }
}
function F2(f1) {
  var a = 200
  console.log(f1())
}
var f1 = F1()
F2(f1) // 100

上述代碼中,自由變量a的值,從函數F1中查找而不是F2,這是因為當自由變量從作用域鏈中去尋找,依據的是函數定義時的作用域鏈,而不是函數執行時。

 

那么自由變量的值如何得到 ?  ——  向父級作用域 (創建該函數的那個父級作用域)尋找

如果父級也沒呢?再一層一層向上尋找,直到找到全局作用域還是沒找到,就宣布放棄。這種一層一層的關系,就是作用域鏈 。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM