關於js的變量,開始的時候我們都會被告知,變量聲明應該在引用該變量之前。關於為什么要這樣做呢,開始的時候本着會用就行的目的,也沒去深究。不過后來經常會發現一些讓人很費解的。。姑且稱為現象吧。先看一段代碼再說:
function a(){ alert(a); var a = 'b' } a();//undefined
此時就會發現不遵守規則的下場了,結果不是你想要的。。當然我們不能說只知道要怎么寫就行了。要知其然也要知其所以然,究其原因,就涉及到兩個概念js作用域和詞法分析了。
都知道js中不存在類似於c++等語言的塊級作用域,例如for循環中定義的變量,其實是屬於當前對象下的屬性,同一對象下可以隨便訪問。只有函數可以限定一個變量的作用范圍,即函數才是變量的作用域。對於函數的變量訪問時遵循作用域鏈的。
js自上而下的執行過程分為兩個詞法分析和執行兩個階段:詞法分析主要包括:分析形參、分析變量聲明、分析函數聲明三個部分(具體關於js詞法分析這里知識簡單說明,請查看我的另一篇文章http://www.cnblogs.com/pqjwyn/p/5365532.html)。通過詞法分析將我們寫的js代碼轉成可以執行的代碼,接下來才是執行。
經過詞法分析的后兩個步驟,會將存在的變量聲明和函數聲明,進行一番處理。具體拿上面的代碼做個例子(只分析變量的部分):
1、分析形參:此處沒有,直接略過(本文只分析變量部分,要是要看完整的部分可以轉到http://www.cnblogs.com/pqjwyn/p/5365532.html)
2、分析變量聲明:此處存在var a = 'b'; 則會給當前函數活動對象(obj)增加屬性a,即:obj.a = undefined。
語法分析之后的結果如下:
function a(){ var a = undefined;//詞法分析之后的結果 alert(a); a = 'b' } a();//undefined
接下來就是執行的過程了,什么你說alert()語句呢?詞法分析顧名思義只分析詞法相關的部分即變量聲明之類的,作為一個執行語句,只有在執行的過程才會執行。也就是說該過程和執行語句還沒扯上關系呢,下面執行步驟的時候才會出場。
所以執行的時候自上而下的順序執行時,當執行到alert(a);時,真正的賦值語句還在下面,所以是undefined。
我好像忘了說變量提升的概念了,其實上面的就是變量提升的實例了,概念就不去下定義了。大家都知道的。再提一句函數提升,詞法分析的時候關於函數聲明的處理與變量聲明的處理不太一致,會一步到位的給當前函數活動對象增加對應函數名的屬性,並重寫該方法。也就是不會像變量那樣先賦值undefined了。說的有點繞,我們還是看代碼,可以先自己看一下執行結果,再看下面的分析:
function a(){ var b = 'a'; function b(){ console.log('b') } alert(b) } a()
簡單說下,詞法分析時對function b的處理:給當前函數活動對象obj增加屬性b,並賦值。即:obj.a = function(){...}
所以詞法分析后的結果成了這個樣子:
function a(){ var b = undefined; b = function b(){ console.log('b') } b = 'a'; alert(b) } a()
然后順序執行的結果也就出來了,b被重新賦值兩次之后的結果為'a'
到此為止,關於變量提升的部分已經結束了。還是那句話,個人愚見,拋磚引玉,共同學習,共同進步。轉載請注明出處。