關於js中變量作用於和變量提升的那些事

一個變量的作用域(scope)是程序源代碼中定義這個變量的區域。
全局變量擁有全局作用域,在javaScript代碼中任何地方都有定義的。
然而在函數內聲明的變量只是在函數內部有定義,他們是局部變量,作用域也只是在局部。

在函數體內,局部變量的優先級要高於全局變量。如果在函數體內重新聲明一個與局部變量重名的變量,局部變量就會覆蓋全局變量的值。

 var scope="全局變量";
    function checkscope(){
        var scope="局部變量";
        function nested(){
            var scope = "嵌套作用域內的局部變量";
            alert(scope);//輸出:嵌套作用域內的局部變量
        }
        nested();
        alert(scope);//輸出:局部變量
    }
    checkscope();
    alert(scope);//輸出:全局變量

從上面的例子中可以看出,局部變量的作用域僅僅在函數內部,出了函數體之後,局部變量就會被銷燬。
在nested()函數中,雖然又聲明瞭一個scope,但是nested()中的scope是局部變量,只是與全局變量的名字相同,並不是全局變量,所以,雖然在該函數中把scope賦值爲”嵌套作用域內的局部變量”,但這僅僅是一個與全局變量名稱相同的一個變量而已,並沒有改變全局變量的值。

我們可以通過以下這個例子來進一步理解函數作用域的問題。

var scope="全局變量";
    function checkscope(){
        var scope="局部變量";
        function nested(){
            scope = "嵌套作用域內的局部變量";
            alert(scope);//輸出:嵌套作用域內的局部變量
        }
        nested();
        alert(scope);//輸出:嵌套作用域內的局部變量
    }
    checkscope();
    alert(scope);//輸出:全局變量

看到這裏是不是有一些懵逼了,這和剛纔不是一樣的嗎,爲什麼第二次彈框不一樣了呢?
上面這部分代碼中,在nested()函數中,我們並沒有用var來聲明scope,所以,在這裏的scope的作用域就被提升了,即我們將checkscope中的scope的值重置了,所以在輸出的時候輸出的結果爲嵌套作用域內的局部變量。

之前學習過c或java等其他編程語言的童鞋會知道,在c語言中會有塊級作用域這個概念。
C語言中塊級作用域是以成對的花括號來界定的,也就是說除了函數代碼塊外,if、for等結構也屬於塊級作用域。
下面這個例子可以幫助我們理解一下:

#include <stdio.h>  
int main() {  
    int x = 1;  
    printf("%d, ", x); // 1  
    if (1) {  
        int x = 2;  
        printf("%d, ", x); // 2  
    }  
    printf("%d\n", x); // 1  
}  

在c或c++、java中,變量的作用域是由成對的花括號來界定的,比如if中的x,在if中,x的值爲2。但是,當程序運行出了if花括號以後,if中的變量x的作用域就結束了,並不會對if以外的x造成影響。但是這在js中是不一樣的~

弄明白了變量的作用域之後再來考慮變量提升就簡單多了。

在Javascript中,函數及變量的聲明都將被提升到函數的最頂部。

在js中,變量的聲明會被解析器悄悄的提升到方法體的最頂部,但是需要注意的是,提升的僅僅是變量的聲明,變量的賦值並不會被提升。

function foo() {  
    if (false) {  
        var x = 1;  
    }  
    return;  
    var y = 1;  
}  
function foo() {  
    var x, y;  
    if (false) {  
        x = 1;  
    }  
    return;  
    y = 1;  
}  

其實上面兩段代碼是一模一樣的。

變量的聲明會被提升,賦值不會被提前。我們需要注意的是,函數的聲明與變量的聲明是不一樣的。函數的函數體也會被一起提升。但是,函數的聲明我們可以用兩種方法。

function test() {  
    var test1 = function () { // 變量指向函數表達式  
        alert("this is test1!");  
    }  
    function test2() { // 函數聲明 函數名爲test2  
        alert("this is test2!");  
    }  
}  
test();

在上面這個例子中,對於test1來說,是聲明瞭一個變量,這個變量指向這個函數表達式,所以解析是會將var test1 提升,而後面對變量的賦值不會被提升。對於test2,解析是會把整個函數體一起提升。所以如果我們在函數體的開始運行兩個函數,test1報錯TypeError “test1 is not a function” ,test2則會彈出this is test2!。

我們可以用這個例子加深一下理解。

<script language="javascript" type="text/javascript">    
    //在全局對象中聲明兩個全局函數,反模式  
    function foo()  
    {  
        alert("global foo");  
    }  

    function bar()  
    {  
        alert("global bar");  
    }  

    //定義全局變量  
    var v = "global var";  

    function hoistMe()  
    {  
        alert(typeof foo); //function  
        alert(typeof bar); //undefined  
        alert(v); //undefined  

        //爲什麼bar函數和變量v是未定義而不是全局變量中定義的相應的函數變量呢?  
         //因爲函數裏面定義了同名的函數和變量,無論在函數的任何位置定義這些函數和  
         //和變量,它們都將被提升到函數的最頂部。  

        foo(); //local foo  
        bar(); //報錯,TypeError "bar is not a function"

        //函數聲明,變量foo以及其實現被提升到hoistMe函數頂部  
        function foo()  
        {  
            alert("local foo");  
        }  

        //函數表達式,僅變量bar被提升到函數頂部,實現沒有被提升  
        var bar = function()  
        {  
            alert("local bar");  
        };  


        //定義局部變量  
         var v = "local";  
    }  

    (function()  
    {  
        hoistMe();  

    })();  

   //函數表達式和變量表達式只是其聲明被提升,函數聲明是函數的聲明和實現都被提升。  
    /**由於函數提升的效果,hoistMe方法相當於 
    function hoistMe() 
    { 
        //函數聲明,變量foo以及其實現被提升到hoistMe函數頂部 
        function foo() 
        { 
            alert("local foo"); 
        } 

         //函數表達式,僅變量bar被提升到函數頂部,實現沒有被提升(同變量提升) 
        var bar = undefined; 

        //變量聲明被提升 
         var v = undefined; 

        alert(typeof foo); //function 
        alert(typeof bar); //undefined 

        foo(); //local foo 
        bar(); //報錯,缺少對象 

        bar = function() 
        { 
            alert("local bar"); 
        }; 

       v = "local"; 

    } 
    */  
</script>  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章