es5變數宣告方式有var, function。通過這兩種方式宣告的變數特點就是具有「變數提公升」的效果,一般想法是乙個變數是先宣告後使用,然而如果採用var 或者function宣告的變數和函式(函式表示式不會提公升)具有提公升的效果。下面詳細說明變數提公升究竟是怎麼產生的。
**在引擎中執行之前都會經歷詞法分析階段,這個階段會將由字元組成的字串分解成若干(對程式語言而言)有意義的**塊,而這些小的**塊我們可以稱他們為詞法單元,舉個栗子給大家,比如:var age = 27;這一句通常會被分解為var、age、=、27、;空是否會被當做詞法單元取決於空格在這門語言中是否有意義。接下來是語法分析階段會將這些詞法單元解析成乙個樹結構我們將這個樹結構稱之為「抽象語法樹」。然後編譯器會進行如下處理,首先遇到var age,編譯器會詢問當前作用域是否已近存在乙個改名字的的變數,如果是的,編譯器就會忽略該宣告,如果不是的話就會要求在當前作用域的集合中宣告乙個新的變數,並且為這個變數命名為age。但是不會立刻給他賦值,賦值是在執行的時候才做的事情。編譯階段實際會吧所有的var宣告的變數提公升到前面。即var age = 27; 可以近似的看成var age;(編譯階段)age = 27;(執行階段)。所以就會產生「變數提公升」的效果了。
關於變數提公升需要注意這幾點:
下面輔以例子來具體說明:
console.log(a)
var a = 3;
執行結果如下:
實際上等同於執行下列**:
var a;
console.log(a)
a = 3;
列印出a的時候,a已近宣告(變數提公升的效果)但是並未賦值,自然就是undefined了,如果沒有變數提公升的效果此處就會報乙個reference erro的錯誤型別了。
再看如下**:
看看執行結果:
下面我們來分下下為什麼是這個結果呢。?
先var 和function都具有變數提公升且根據我們上面的第二條原則function > var 所以第一次列印console.log(f)此時的f是乙個函式;
接下來是執行f()自然就會得到f函式內列印的字串'i am function f'再接下來就是給f賦值了此時的f = 27;列印f就會得到數字27,然後又將f的值改為2,再執行f()而此時f已近不是乙個函式了,所以控制台會抱乙個typeerror的錯誤,表示我們對f的用法錯了(關於各個錯誤型別我們後面會有一篇文章專門說明)。
下面再看看我們所說的第三點:
在函式foo中此時傳入的引數age=27,根據我們上述的第三點即函式引數 > 函式內部變數提公升。所以在函式內部列印出的age是傳入的引數27,最後一句列印出的age自然就是0了。
有關於函式表示式是否會有變數提公升,我看了很多人寫的部落格是說函式表示式並不會有變數提公升,我並不贊同這個觀點,我覺得函式表示式也會產生變數提公升,事實上只要是用var 與function宣告的變數都會產生變數宣告,但切記用var 宣告的變數不會立馬賦值。看如下**。
實際上在這兒執行的**等同下面的**:
var foo;
console.log(foo)
foo = function ()
所以函式表示式也同樣有變數提公升的效果。 es5的scope和變數提公升
最近在學習es6,看到es6的作用域 新增的let和const宣告命令和es5有了很大的不同,所以想著總結下es5的作用域和變數提公升。es5是沒有塊級作用域的,當你在函式外宣告乙個變數,那麼你在 任何地方都能訪問到,這個變數也被稱為全域性變數,擁有全域性作用域 當你在乙個函式內部宣告變數的話,那麼...
變數宣告提公升 Vs 函式宣告提公升
先看以下 1 var in window a in window console.log in window 2 var in window a in window console.log in window if a in window 3 var a var in window a in win...
JS變數宣告提公升
js的變數作用域是離它最近的封閉語塊或 塊,包含他們內部的函式.在 塊中宣告會被隱式的提公升到封閉函式的頂部 1 function 6 var y 1 7 上面的 會被js解釋成下面的格式 1 function 8 有時候我們會不小心的在函式內部重新宣告了已有的變數 function text x ...