JavaScript全局变量与局部变量

    |     2021年5月19日   |   html/css/js   |     0 条评论   |    777

谈 JavaScript 全局变量和局部变量之前,先记住三件事:查找变量走的是作用域链;用 var 时没有块级作用域;函数里声明的变量在整个函数体都有效。

ES6 的 let / const 才真正有块级作用域。 下文例子全部沿用原文的 var,这是面试里仍经常被追问的经典行为。

一、作用域链

inner 里的 alert(rain) 会一层层往外找:inner → rainman → 全局。 内层没定义就继续向外,直到全局对象上的 rain = 1,最终弹出 1。

<script type="text/javascript">
    var rain = 1;
    function rainman(){
        var man = 2;
        function inner(){
            var innerVar = 4;
            alert(rain);
        }
        inner();    //调用inner函数
    }
    rainman();    //调用rainman函数
</script>

这条链上有三个对象,顺序是 inner、rainman、window。引擎要的是变量 x 时,从链头第一个对象找起,没有再找下一个。

二、局部变量盖住同名全局变量

函数体内同名局部变量优先级更高。下面 check 里弹出 100,外面仍是 1:

<script type="text/javascript">
    var rain = 1;    //定义全局变量 rain
    function check(){
        var rain = 100;    //定义局部变量rain
        alert( rain );       //这里会弹出 100
    }
    check();
    alert( rain );    //这里会弹出1
</script>

三、var 没有块级作用域

这是相对 C 系语言更「松」的地方。if / for 里用 var 声明的 i、j、k,作用域仍是整个 rainman 函数:

<script type="text/javascript">
    function rainman(){
        // rainman函数体内存在三个局部变量 i j k
        var i = 0;
        if ( 1 ) {
            var j = 0;
            for(var k = 0; k < 3; k++) {
                alert( k );    //分别弹出 0 1 2
            }
            alert( k );        //弹出3
        }
        alert( j );            //弹出0
    }
</script>

循环结束后 k 是 3,if 外面也能读到 j。若改成 let k,循环外再读 k 会 ReferenceError。

四、函数内声明的变量整函数可见

内层 man 改的是外层 rain 里的 x,所以弹出 100:

<script type="text/javascript">
    function rain(){
        var x = 1;
        function man(){
            x = 100;
        }
        man();        //调用man
        alert( x );    //这里会弹出 100
    }
    rain();    //调用rain
</script>

同一规则会造成「先读后声明」的错觉:

<script type="text/javascript">
    var x = 1;
    function rain(){
        alert( x );        //弹出 'undefined',而不是1
        var x = 'rain-man';
        alert( x );        //弹出 'rain-man'
    }
    rain();
</script>

因为 var x 在整个 rain 里都有效,同名全局 x 被挡住。 第一次 alert(x) 时局部 x 只完成了声明、尚未赋值,所以是 undefined。等价于:

function rain(){
    var x;
    alert( x );
    x = 'rain-man';
    alert( x );
}

五、不用 var 就是全局变量

赋值给一个从未声明的标识符,会在全局对象上创建属性。新手常这样留下一堆全局变量:

<script type="text/javascript">
    function rain(){
        x = 100;    //声明了全局变量x并进行赋值
    }
    rain();
    alert( x );    //会弹出100
</script>

严格模式('use strict')下这行会报 ReferenceError,建议养成始终声明的习惯。

六、全局变量是 window 的属性

浏览器里用 var 声明的全局,等价于给 window 添属性:

<script type="text/javascript">
    var x = 100 ;
    alert( window.x );//弹出100
    alert(x);
</script>

等同于:

<script type="text/javascript">
    window.x = 100;
    alert( window.x );
    alert(x)
</script>
规则 含义 例子里的结果
作用域链 由内向外找标识符 inner 能读到全局 rain=1
同名遮蔽 局部优先于全局 函数内 100,函数外 1
无块级(var) if/for 里的 var 仍属整个函数 循环外仍能读到 k、j
声明提升 整个函数都能看到该绑定 赋值前读取得到 undefined
漏写 var 隐式全局 函数外也能 alert(x)

一句话总结:用 var 时变量只认函数作用域:沿作用域链查找,局部盖全局,块挡不住,漏写 var 就会漏到 window 上。

转载请注明来源:JavaScript全局变量与局部变量
本文链接地址:https://ai.zhousir.top/?p=3248
回复 取消