1. 程式人生 > 其它 >JavaScript預編譯(執行期上下文)

JavaScript預編譯(執行期上下文)

什麼是預編譯?

前端同學都知道js裡有個叫變數宣告提升的概念,其實這就是預編譯造成的。預編譯也叫執行期上下文。當js程式碼執行的時候,實際上是執行在執行期上下文裡面,執行期上下文包含三種。

  • 全域性上下文(Global Object,即全域性程式碼,簡稱GO)
  • 函式上下文 (Activation Object,每個函式在執行的前一刻會建立屬於自己的執行期上下文,簡稱AO)
  • eval方法也會建立新的執行期上下文 (用的不多,這裡就不說它了)
  var a = 1;
  var b = 2;
  
  function add(x,y) {
	  return x + y;
  }
  
  add(1,2)
  
  // 1. 執行程式碼,首先建立一個全域性的GO
  // 2. 執行add函式的前一刻建立屬於add函式的AO

執行期上下文棧

  1. 全域性程式碼執行前,JS就會建立一個棧來儲存管理所有的執行上下文物件
  2. 全域性執行期上下文確定後,把它新增到棧中(棧底)
  3. 當函式的執行期上下文建立完後,把它新增到棧中(棧頂)
  4. 當前函式執行完畢,在棧頂把這個函式的執行期上下文移出
    • 函式執行中,遇到return直接終止可執行的程式碼,會直接將當前上下文彈出棧
  5. 全部程式碼執行完畢,棧裡就只剩全域性的執行期上下文了
  6. 當瀏覽器視窗關閉,移出全域性的執行期上下文

執行期上下文建立過程

AO

  1. 建立AO物件(Activation Object)
  2. 找形參和變數宣告,將變數和形參名作為 AO 屬性名,值為 undefined
  3. 將實參和形參相統一
  4. 在函式體裡面找函式宣告,值賦予函式體
  function fn(a,b){
    console.log(a);
    c = 0;
    var c;
    a = 3;
    b = 2;
    console.log(b);
    function b(){};
    function d(){};
    console.log(b);
  }
  fn(1,2)
  /*
	建立過程:
		1. 建立AO物件
		AO = {

		}
		2. 找形參和變數宣告,將變數和形參名作為 AO 屬性名,值為 undefined
		AO = {
			a:undedfined,
			b:undefined,
			c:undefined
		}
		3.將實參和形參相統一
		AO = {
			a:1,
			b:2,
			c:undefined
		}
		4. 在函式體裡面找函式宣告,值賦予函式體
		AO = {
			a:1,
			b:function b(){},
			c:undefined,
			d:function b(){}
		}
  */
  /*
    函式執行過程:
	function fn(a,b){
	  console.log(a); // 1
	  c = 0;          // AO的c變成0
	  var c;		  // AO建立過了,忽略
	  a = 3;          // AO的a變成3
	  b = 2;          // AO的b變成2
	  console.log(b); // 2
	  function b(){}; // AO建立過了,忽略
	  function d(){}; // AO建立過了,忽略
	  console.log(b); // 2
	}
  */
	
	

GO

  1. 建立GO物件(Global Object)
  2. 找形參和變數宣告,將變數和形參名作為 GO 屬性名,值為 undefined
  3. 在函式體裡面找函式宣告,值賦予函式體
  console.log(a)
  var a= 1;
  var b;
  function c() {};
  function b() {};
  console.log(c)
  console.log(b)
  b = 2;
  console.log(a)
  console.log(b)
  /*
	建立過程:
		1. 建立AO物件
		AO = {

		}
		2. 找形參和變數宣告,將變數和形參名作為 AO 屬性名,值為 undefined
		AO = {
			a:undedfined,
			b:undefined,
			c:undefined
		}
		3. 在函式體裡面找函式宣告,值賦予函式體
		AO = {
			a:undedfined,
			b:function b(){},
			c:function c(){},
		}
  */
  /*
    函式執行過程:
	console.log(a) // undefined
	var a= 1;      // GO的a變成1
	var b;   	   // GO建立過了,忽略
	function c();  // GO建立過了,忽略
	function b();  // GO建立過了,忽略
	console.log(c) // function c() {}
	console.log(b) // function b() {}
	b = 2;         // GO的b變成2
	console.log(a) // 1
	console.log(b) // 2
  */


其實全域性對比函式的執行期上下文建立過程就是少了個形參和實參統一,其餘的都一樣