關於JavaScript變量提升的理解

分類:IT技術 時間:2016-10-19

  廢話不說,直接上代碼(這是在JavaScript面對對象編程指南上面看到的一個例子)

var a=123;
function f(){
  alert(a);
  var a=1;
  alert(a);          
}
f();

  書上的解釋是這樣的:當javascript執行過程進入新函數時,這個函數內被聲明的所有變量都會被移動導到函數最開始的地方。這種現象叫做提升。且被提升的只有變量的聲明。

上面這個例子可以等價於:

var a=123;
function
f(){   var a;
  alert(a);
  a=1;
  alert(a);
}
f(); //答案很顯然是1

  書上只是把它當做一個定義,告訴讀者必須記住。其實我們可以從JavaScript編譯器的原理出發,搞清楚這段代碼到底是怎麽編譯的就不用死記了!!

  那麽我們就首先簡單的談一下JavaScript代碼是怎樣編譯執行的(淺顯的談)首先JavaScript代碼的編譯執行主要由JavaScript引擎,編譯器,作用域三個負責。

  引擎:從頭到尾負責整個JavaScript程序的編譯和執行過程;

  編譯器:負責語法分析及代碼生成等;

  作用域:負責收集並維護由所有聲明的變量組成的一系列查詢,並實施一套非常嚴格的規則,確定當前執行的代碼對這些變量的訪問權限。

  可能不是很明白,我們先看一下傳統的編譯器編譯的過程,一段代碼執行大概需經過下面三個過程(其實際過程肯定比這復雜很多):

  1,詞法分析:將由字符組成的字符串分解成有意義的代碼塊。而這些代碼塊被稱作詞法單元。例如:var a=2;這段代碼會被分解成var,a,=,2,;這些詞法單元。

  2,語法分析:將詞法單元流轉換成一個由元素逐級嵌套所組成的代表了程序語法結構的“抽象語法樹”;

  3,代碼生成:將“抽象語法樹”轉換成為可執行代碼的過程。這個過程與語言和目標平臺相關。

  由於JavaScript不同於其他有專用編譯器的語言如C(如hello.c是先編譯成可執行的hello.0程序,這兒階段聲明賦值都已經操作完成,如果編譯成功就能執行。)而JavaScript代碼編譯階段只是一個對變量的聲明階段,其賦值什麽的操作是在代碼實際執行的時候才進行的。這也是為什麽JavaScript代碼寫完後必須執行才能知道有沒有錯誤。

  好了相關概念介紹基本差不多了,那上面這段代碼該如何用編譯器去理解呢!我們先來簡單的理解var a=2;這段代碼。首先這段代碼由交給編譯器:編譯器工作就是負責語法分析,它首先會對var a進行聲明,然後去它的作用域中尋找之前有沒有聲明a,如果已經聲明了就忽略這個聲明,如果沒有找到就在作用域中聲明一個新的變量a,然後編譯器就將代碼編譯成引擎可以運行的代碼,這些代碼用來處理a=2;引擎拿到代碼後首先會在作用域中尋找有沒有a變量,如果有就使用這個變量a,如果沒有就會拋出錯誤。這段過程總結一下就是代碼首先在編譯器中聲明相關變量,然後交給引擎,引擎便對這些變量進行操作(賦值等)。

  有了上面的分析過程我們再來看第一段代碼:書上之所以能把它改寫成下面那段代碼,就是因為這段代碼首先會在編譯器進行編譯,編譯的過程就是將這段代碼中作用域相關的各個變量進行聲明,這是在引擎執行代碼前工作的,所以改寫的時候var a會提到作用域的最前面,等編譯完成後JavaScript引擎才會進一步執行代碼也就是對變量進行各種賦值等操作。這個過程就是書上面提到那個詞“提升”。其他的一些細節就不用贅述了。第二段代碼應該能很清楚的理解了。(註意:提升只能在變量自己的作用域裏面提升,不能越過作用域提升到外面來。)。

  再給一個練習的例子:

f();  //Hello World!
var f;
function f(){
  aler("Hello World!");  
}
f=function(){
  alert("Hello Javascript!");
}

  改寫形式我就不寫了,自己完全可以寫出來。

 

 

  

 


Tags:

文章來源:


ads
ads

相關文章
ads

相關文章

ad