1. 程式人生 > >函數聲明的提升和變量聲明提升

函數聲明的提升和變量聲明提升

details 函數表達式 提前 函數 變量 語句 變量定義 detail on()

註:本文轉自:http://blog.csdn.net/qq673318522/article/details/50810650僅做學習方便,沒有任何商業目的;

變量聲明提升

1、變量定義

可以使用var定義變量,變量如果沒有賦值,那變量的初始值為undefined

2、變量作用域

變量作用域指變量起作用的範圍。變量分為全局變量和局部變量。全局變量在全局都擁有定義;而局部變量只能在函數內有效。
在函數體內,同名的局部變量或者參數的優先級會高於全局變量。也就是說,如果函數內存在和全局變量同名的局部變量或者參數,那麽全局變量將會被局部變量覆蓋。
所有不使用var定義的變量都視為全局變量

3、函數作用域和聲明提前

JavaScript的函數作用是指在函數內聲明的所有變量在函數體內始終是有定義的,也就是說變量在聲明之前已經可用

,所有這特性稱為聲明提前(hoisting),即JavaScript函數裏的所有聲明(只是聲明,但不涉及賦值)都被提前到函數體的頂部,而變量賦值操作留在原來的位置。如下面例子:
註釋:聲明提前是在JavaScript引擎的預編譯時進行,是在代碼開始運行之前。

1 var scope = ‘global‘;
2 function f(){
3     console.log(scope);
4     var scope = ‘local‘;
5     console.log(scope);
6 }

由於函數內聲明提升,所以上面的代碼實際上是這樣的

1 var scope = ‘global‘;
2 function f(){ 3 var scope; //變量聲明提升到函數頂部 4 console.log(scope); 5 scope = ‘local‘; //變量初始化依然保留在原來的位置 6 console.log(scope); 7 }

經過這樣變形之後,答案就就非常明顯了。由於scope在第一個console.log(scope)語句之前就已經定義了,但是並沒有賦值,因此此時scope的指是undefined.第二個console.log(scope)語句之前,scope已經完成賦值為’local’,所以輸出的結果是local

函數聲明提升

1、函數的兩種創建方式

  • 函數聲明
  • 函數表達式

函數聲明語法

f(‘superman‘);
function f(name){
    console.log(name);
}

運行上面的程序,控制臺能打印出supemran
函數表達式語法

1 f(‘superman‘);
2 var f= function(name){
3     console.log(name);
4 }

運行上面的代碼,會報錯Uncaught ReferenceError: f is not defined(…),錯誤信息顯示說f沒有被定義。
為什麽同樣的代碼,函數聲明和函數表達式存在著差異呢?
這是因為,函數聲明有一個非常重要的特征:函數聲明提升,函數聲明語句將會被提升到外部腳本或者外部函數作用域的頂部(是不是跟變量提升非常類似)。正是因為這個特征,所以可以把函數聲明放在調用它的語句後面。如下面例子,最終的輸出結果應該是什麽?:

1 var getName = function(){
2     console.log(2);
3 }
4 function getName (){
5     console.log(1);
6 }
7 getName();

可能會有人覺得最後輸出的結果是1。讓我們來分析一下,這個例子涉及到了變量聲明提升函數聲明提升。正如前面說到的函數聲明提升,函數聲明function getName(){}的聲明會被提前到頂部。而函數表達式var getName = function(){}則表現出變量聲明提升。因此在這種情況下,getName也是一個變量,因此這個變量的聲明也將提升到底部,而變量的賦值依然保留在原來的位置。因此上面的函數可以轉換成下面的樣子:

1 var getName;    //變量聲明提升
2 function getName(){    //函數聲明提升到頂部
3     console.log(1);
4 }
5 getName = function(){    //變量賦值依然保留在原來的位置
6     console.log(2);
7 }
8 getName();    // 最終輸出:2

所以最終的輸出結果是:2。在原來的例子中,函數聲明雖然是在函數表達式後面,但由於函數聲明提升到頂部,因此後面getName又被函數表達式的賦值操作給覆蓋了,所以輸出2

 1    var sum =0;
 2     var a = 10;
 3     all1 = 1000;
 4     function test(){
 5         console.log(a);//10
 6         all2=200;
 7         console.log(foo());//2//foo是一個函數,解析的時候會提升,所以能夠訪問到
 8         function foo() {
 9             return 2;
10         };
11     }
12     test();

函數聲明的提升和變量聲明提升