最通俗易懂的javascript變量提升


1 a = 'ghostwu';
2 var a;
3 console.log( a );

在我沒有講什么是變量提升,以及變量提升的規則之前, 或者你沒有學習過變量提升,如果按照現有的javascript理解, 對於上述的例子,你可能會認為第3行代碼的輸出結果應該是undefined,  因為第二行是var a; 聲明變量,但是沒有賦值,所以a的值是undefined, 但是正確的結果是ghostwu. 至於為什么,請繼續往下看!

1 console.log( a );
2 var a = 'ghostwu';

對於上面這個例子,第一行代碼,你可能認為報錯, 因為在輸出a之前,沒有定義a變量, 但是正確的結果是undefined. 嗯,好像有點莫名奇妙,javascript太bug了.

要搞清楚為什么,首先我們要明確以下2點:

  • javascript代碼並不是一行一行往下執行的.
  • javascript執行分為2個步驟: 
    • 編譯(詞法解釋/預解釋)
    • 執行

其次,當我們碰到 var a = "ghostwu" 定義一個變量的時候, 其實js把這句話看成是2個階段的事,  var a 發生在編譯階段, a = 'ghostwu'發生在執行階段. 然后 var a會被提升到當前作用域的最前面,  a = 'ghostwu'留在原地等待執行階段,所以:

1 a = 'ghostwu';
2 var a;
3 console.log( a );
4 
5 //上面這段代碼經過編譯之后,變成下面這樣
6 
7 var a;  //被提升到當前作用域的最前面
8 a = 'ghostwu'; //留在原地,等待執行
9 console.log( a ); 
1 console.log( a ); 
2 var a = 'ghostwu';
3 
4 //上面這段代碼,經過編譯之后,變成下面這樣
5 
6 var a;
7 console.log( a );
8 a = 'ghostwu';

看完編譯后的代碼,你明白了嗎?

在接着講下面之前,我們先明確函數常見的2種定義方式:

1         //函數聲明, 形如:
2         function show(){
3             console.log( '函數聲明方式' );
4         }
5 
6         //函數表達式, 形如:
7         var show = function(){
8             console.log( '表達式方式' );
9         }

因為表達式和函數聲明,在編譯階段,會產生不同的解釋效果。

1         show();
2         function show(){
3             console.log( a );
4             var a = 'ghostwu';
5         }

對於上面這段代碼,會在編譯階段,如何解釋呢?記住下面這句話就行了:

函數聲明會被提升

所以,上面的代碼,經過編譯之后,就變成了下面這樣:

       function show(){    //函數聲明被提升到 當前作用域的最前面
            var a;    //var聲明被提升到當前作用域的最前面, 注意,他不會提升到函數的外面, 因為當前的作用域是在函數中
            console.log( a );
            a = 'ghostwu';
        }
        show();

所以,上面的結果就是undefined;

對於函數表達式,是不會提升的, 看下面的例子:

 1 show(); //報錯,show is not a function
 2 var show = function(){
 3  console.log( 'ghostwu' );
 4 }
 5 //對於上面這段表達式代碼,經過編譯之后:
 6 var show;
 7 show();  //執行之后就是 undefined(), 所以在表達式定義之前,調用函數報錯了
 8 show = function(){
 9   console.log( 'ghostwu' );  
10 }
1         show(); //你好
2         var show;
3         function show(){
4             console.log( '你好' );
5         }
6         show = function(){
7             console.log( 'hello' );
8         }

上面這段代碼,結果為什么會是 '你好'?

因為: 當出現同名的函數聲明,變量聲明的時候, 函數聲明會被優先提升,變量聲明會被忽略。 所以經過編譯之后,就變成:

1         function show(){
2             console.log( '你好' );
3         }
4         show(); //你好
5         show = function(){
6             console.log( 'hello' );
7         }
8         show();//如果這里在調用一次,就是hello, 因為show函數體在執行階段 被 重新賦值了    

如果有同名的函數聲明,后面的會覆蓋前面的,如下:

 1         show(); //how are you
 2         var show;
 3         function show(){
 4             console.log( 'hello' );
 5         }    
 6         show = function(){
 7             console.log( '你好' );
 8         }
 9         function show(){
10             console.log( 'how are you!' );
11         }
12 //上面的代碼經過編譯之后,變成如下形式:
13         function show(){
14             console.log( 'how are you!' );
15         }
16         show(); //how are you
17         show = function(){
18             console.log( '你好' );
19         }
20         show(); //如果在這里再執行一次,結果:你好
 1 //思考題: 請問下面的結果是什么? 為什么? 寫下你的答案
 2          show();
 3           var a = true;
 4           if( a ){
 5               function show(){
 6                   console.log( 1 );
 7               }
 8           }else {
 9               function show(){
10                  console.log( 2 );
11             }
12          }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM