1. 程式人生 > >變數宣告系列之ES5(變數提升)

變數宣告系列之ES5(變數提升)

變數宣告恐怕是我們日常開發中最最經常遇到的了,那今天我們就來總結下現在js一共有哪幾種變數宣告的方式以及各個宣告方式的特點。這個變數宣告系列分兩篇文章,一篇寫ES5(var,function)的變數宣告方式及其特點,下一篇寫ES6的變數宣告方式(let,const,class,import)及其特點。

ES5變數宣告方式有var, function。通過這兩種方式宣告的變數特點就是具有“變數提升”的效果,一般想法是一個變數是先聲明後使用,然而如果採用var 或者function宣告的變數和函式(函式表示式不會提升)具有提升的效果。下面詳細說明變數提升究竟是怎麼產生的。

程式碼在引擎中執行之前都會經歷詞法分析

階段,這個階段會將由字元組成的字串分解成若干(對程式語言而言)有意義的程式碼塊,而這些小的程式碼塊我們可以稱他們為詞法單元,舉個栗子給大家,比如:var age = 27;這一句通常會被分解為var、age、=、27、;空是否會被當做詞法單元取決於空格在這門語言中是否有意義。接下來是語法分析階段會將這些詞法單元解析成一個樹結構我們將這個樹結構稱之為“抽象語法樹”。然後編譯器會進行如下處理,首先遇到var age,編譯器會詢問當前作用域是否已近存在一個改名字的的變數,如果是的,編譯器就會忽略該宣告,如果不是的話就會要求在當前作用域的集合中宣告一個新的變數,並且為這個變數命名為age。但是不會立刻給他賦值,賦值是在執行的時候才做的事情。編譯階段
實際會吧所有的var宣告的變數提升到前面。即var age = 27; 可以近似的看成var age;(編譯階段)age = 27;(執行階段)。所以就會產生“變數提升”的效果了。

關於變數提升需要注意這幾點:

  • 在js中用var ,function宣告的變數都將被提到函式的最頂部。(但是不會初始化
  • 函式宣告的優先順序大於變數宣告的優先順序(function > var
  • 在函式內部變數提升的優先順序會小於函式引數(函式引數 > 函式內部變數提升

下面輔以例子來具體說明:

    console.log(a)
    var a = 3;

執行結果如下:


實際上等同於執行下列程式碼:

    var a;
    console.log(a)
    a = 3;

打印出a的時候,a已近宣告(變數提升的效果)但是並未賦值,自然就是undefined了,如果沒有變數提升的效果此處就會報一個reference erro的錯誤型別了。

再看如下程式碼:

<script>

   console.log(f)

    f()
    var f = 27;

   function f(){
       console.log('I am function f')
   }

   console.log(f);
   f = 2;
   f();

</script>

看看執行結果:


下面我們來分下下為什麼是這個結果呢。?

先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的用法錯了(關於各個錯誤型別我們後面會有一篇文章專門說明)。

下面再看看我們所說的第三點:

code:

var age = 0;
   function foo(age) {
       console.log(age);
       var age = 20;
   }

    foo(27)
    console.log(age)

在函式foo中此時傳入的引數age=27,根據我們上述的第三點即函式引數 > 函式內部變數提升。所以在函式內部打印出的age是傳入的引數27,最後一句打印出的age自然就是0了。

有關於函式表示式是否會有變數提升,我看了很多人寫的部落格是說函式表示式並不會有變數提升,我並不贊同這個觀點,我覺得函式表示式也會產生變數提升,事實上只要是用var 與function宣告的變數都會產生變數宣告,但切記用var 宣告的變數不會立馬賦值。看如下程式碼。

code:

 console.log(foo)
    
    var foo = function () {
        console.log('I am a function foo')
    }

實際上在這兒執行的程式碼等同下面的程式碼:

  var foo;
    console.log(foo)
    
    foo = function () {
        console.log('I am a function foo')
    }
所以函式表示式也同樣有變數提升的效果。