1. 程式人生 > >JavaScript的預編譯過程

JavaScript的預編譯過程

JavaScript在執行時,要經歷三步
1. 語法分析 2.預編譯 3.解析執行(自上而下)

JavaScript預編譯

先思考這麼一個題

function fn (a) {
  console.log(a);

  var a = 123;

  console.log(a);

  function a(){};

  console.log(a);

  var b =function (){};

  console.log(b);
}
fn(1);

預編譯四部曲

  1. 建立AO物件 Activation Object(執行期上下文)
  2. 找形參和變數宣告,將變數和形參名作為AO屬性名,值為undefined
  3. 將實參值和形參統一
  4. 在函式體裡面找函式宣告,值賦予函式體

這四步的權重比4>3>2>1,也就是一個覆蓋的過程.
函式宣告在變數宣告的前面

函式宣告才存在變數提升。即function a(){};,而var b =function (){};不會提升。

詳細分析

先看一個面試中常遇到的問題

console.log(a); // function a(){}
var a = 1;
function a(){};

逐行執行,在AO中是:

AO{
  a: undefied
}
AO{
  a: function(){}
}

換一換

var
a = 1; console.log(a); // 1 function a(){};

逐行執行,在AO中是:

AO{
  a: undefied
}

AO{
  a: function(){}
}

// js是自上而下執行的,先執行var a = 1; 所有AO中的a就被覆蓋
AO{
  a: 1
}

按步驟分析文章開頭的例子

  • 第一步
AO{
}
  • 第二步
AO{
  a: undefined,
  b: undefined
}
  • 第三步
AO{
  a: 1,
  b: undefined
}
  • 第四步
AO{
  a: function
a(){
}, b: undefined }

解釋執行

執行的時候:

AO{
  a: function a(){},
  b: undefined
}
// a = 123;
AO{
  a: 123,
  b: undefined
}

結果:

function fn (a) {
  console.log(a); // function(){}

  var a = 123;

  console.log(a); // 123

  function a(){};

  console.log(a); // 123

  var b =function (){};

  console.log(b); // function(){}
}
fn(1);

加入window,全域性環境

global = 100;
function fn() {
  console.log(global);
  global = 200;
  console.log(global);
  var global = 300;
}
fn();
var global;

在全域性環境中會生成一個 GO物件 (Global Object),還是按照上面的四步執行。

GO {
  global: undefined  
}

// 執行到 global = 100 :

GO {
  global: 100  
}

當執行fn之前會先生成一個AO:

AO {
  global: undefined  
}

所以第一次列印globalundefined

這個時候雖然全域性變數中的global已經是100,但是fn函式中自己有global變數,所以不會引用全域性中的。

當執行到global = 200 :

AO {
  global: 200  
}

所以第二次列印global200

最後思考一個問題

function fn(){
  var a = b = 100;
  console.log(window.a);
  console.log(window.b);
}

var a = b =100;
先將100賦值給b,即b=100,此時b沒有宣告就被賦值,在JavaScript中如果一個變數未宣告就直接賦值,那麼這個變數就是個全域性變數。