Js 執行上下文和做用域

1.執行上下文和執行棧

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

執行上下文的生命週期包括三個階段:建立階段→執行階段→回收階段,咱們重點介紹建立階段。瀏覽器

建立階段(當函數被調用,但未執行任何其內部代碼以前)會作如下三件事:安全

  • 建立變量對象:首先初始化函數的參數arguments,提高函數聲明和變量聲明。閉包

  • 建立做用域鏈函數

  • 肯定this指向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
*/

 

這是由於當函數執行的時候,首先會造成一個新的私有的做用域,而後依次按照以下的步驟執行:spa

  • 若是有形參,先給形參賦值線程

  • 進行私有做用域中的預解釋,函數聲明優先級比變量聲明高,最後後者會被前者所覆蓋,可是能夠從新賦值code

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

 

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

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,這是由於當自由變量從做用域鏈中去尋找,依據的是函數定義時的做用域鏈,而不是函數執行時。

 

那麼自由變量的值如何獲得 ?  ——  向父級做用域 (建立該函數的那個父級做用域)尋找

若是父級也沒呢?再一層一層向上尋找,直到找到全局做用域仍是沒找到,就宣佈放棄。這種一層一層的關係,就是做用域鏈 。

相關文章
相關標籤/搜索