JS難點之hoist

這篇博文是以前在CSDN寫的,如今移至sf。編程

有過C或者Java類編程經驗的同窗,對於「先聲明後使用」的規則很熟悉,若是使用未聲明的變量或者函數,編譯時程序會報錯!可是,JavaScript倒是一個‘大奇葩’,能夠在變量或者函數聲明以前使用,如今根據個人理解在作一下說明。微信

首先說明JS的hoist分爲變量hoist函數hoist兩種。函數

1、變量hoist

看一段程序code

       var a=10;  
       function fun(){  
         console.log(a);  
         var a=100;  
         console.log(a);  
      }  
       fun();//undefined   100  
       console.log(a);//10  

 

咱們知道在js中,做用域分爲全局做用域和函數做用域兩種(ES6新特性,增長了塊級做用域,另作說明)。全局變量聲明有三種方式:對象

  • var(關鍵字)+變量名(標識符)方式在function外部聲明,顯示聲明
  • 沒有使用var,直接給標識符賦值,隱式聲明
  • 使用window全局對象來聲明,全局對象的屬性也應是全局變量 eg:window.test=50; alert(test);

  

好,很顯然,var a=10;在程序中是全局變量。那麼,按照咱們正常的邏輯輸出結果爲:10  100  10。可是,實際輸出結果爲:undefined 100  10,實際上是JS解析器的解析緣由,它會將當前做用域中聲明的全部變量和函數,放在做用域的最開始處。可是變量只有其聲明被提早在做用域的最開始處,賦值結果仍然還在原來位置。上述代碼對於解析器來講,實際上是:ip

       var a=10;  
       function fun(){
          var a;  
          console.log(a);  
          a=100;  
          console.log(a);  
       }  

       fun();//undefined   100  
       console.log(a);//10

2、函數hoist

 
講完變量hoist,如今再講一下函數hoist,函數hoist又分爲兩種狀況。一種是函數聲明,另外一種是函數做爲值賦值給變量作用域

先說第一種狀況:io

   fun();//2  

   function fun(){console.log(2);} 

在這種狀況下,能夠看出,函數JS解釋器容許在函數聲明以前使用函數,其實也就說明,在這種狀況,不只函數名提早了,同時,函數體也被提早。因此能夠上述代碼能夠執行。再說第二種狀況:console

     fun();  
     var fun=function(){  
        console.log(2);  
     }

結果爲:Uncaught TypeError: fun is not a function  能夠看出在此例中,函數只是變量聲明聲明提早,可是賦值沒有提早,而且被提早的變量默認爲undefined,因此報的錯誤類型爲「typeerror」,由於undefined不是函數,不能被調用。編譯

3、變量名和函數名相同時的hoist

       function fun(){console.log(1);}  
       fun();//2  
       function fun(){console.log(2);}  
       fun();//2  
       var fun=100;  
       console.log(fun);//100  
       fun();//報錯

在此例中,函數名和變量名相同,都是fun,都會提早,那麼在提早時,有什麼須要注意的地方呢? 

  • 函數聲明比變量聲明更置頂
  • 聲明過得變量不會重複聲明

  

因此上述代碼等效於:

function fun(){console.log(1);}  
     function fun(){console.log(2);}//函數體覆蓋上一層函數體  
     var fun;//實際無效  
     fun();  
     fun();  
     fun=100;  
     console.log(fun);  
     fun();

以上就是本人對於JS的hoist問題的理解,若是哪位同窗,發現其中有誤,歡迎指正!個人微信號爲:Alfred-kai。 

相關文章
相關標籤/搜索