关于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   
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>  

你可能感兴趣的:(javascript)