首页 > javascript中关于函数中赋值的疑问

javascript中关于函数中赋值的疑问

<script type="text/javascript">
        var str1="b";
        function test(){
            alert(str1); 
            var str1 = "c";
        }
        test();
</script>

对于上面这段代码,为什么单单var str1 = "c"就会使得str1的值为undefined呢?
主要的疑惑和请教:


这是JavaScript的变量声明提升效果 - hoisting
以上代码在运行时会变为这样

<script type="text/javascript">
        var str1="b";
        function test(){
            var str1;
            alert(str1); 
            str1 = "c";
        }
        test();
</script>

js只有函数作用域,所以alter(str1)时现在本函数作用域查找变量,此时只是进行了var str1 那么返回的就是undefined,如果本函数作用域没有此变量的声明,才会依据作用域链向外寻找。


请注意js的变量声明有hoisting 变量提升...函数内执行的相当于

var str1;
alert(str1);
str1 = 'a';


题主的第一个疑问,是关于变量提升的问题。

原代码

var str1="b";
        function test(){
            alert(str1); 
            var str1 = "c";
        }
        test();

等同于

function test(){
            var str1;
            alert(str1); 
            str1 = "c";
        }
var str1;
str1="b";
test();

简单点说,JavaScript中只有用var声明的变量(ES6里新出的声明变量的let和声明常量的const都没这个讲究)和函数声明(注意!是函数声明!不包括var f = function(){}等等这样的函数表达式!)才有变量提升现象。

其中,函数声明优先级高于用 var 声明的变量,JavaScript引擎会先解析。

对函数声明来说,变量提升会带着函数体一起放到区域执行环境的前端;对变量声明来说,只提升变量,不提升声明。(比如你代码中的str1声明被提前,赋值还保留在原来的那一行。)

题主的第二个问题,是关于执行环境和作用域链的问题。

此过程中全局变量str1没变化,因为不关它事。

作用域链其实是个保证访问顺序的东西。这顺序是由里往外,由下至上的。作用域链的前端始终是当前执行代码所在环境的变量对象。在当前环境中拿到了它想要的值(别管是什么值,哪怕是个只声明未赋值的undefined),就不会沿着作用域链继续向上查找了。


前面的回答都不错
补充局部变量与全局变量的关系。
设置一个全局变量,需在任何函数之外用var声明,对所有函数有效。
设置一个局部变量,就在需要的地方var声明。

var a=1;
function f(){
    var a=2;
    alert(a);
}
alert(a);

上面的代码中,全局变量a的值为1。局部变量a为2。
在一个function中,如果全局变量与局部变量重名,局部变量优先级高。所以在f()的alert中,a的值为2。
然而局部变量顾名思义,就是只在局部范围内生效的函数。所以a=2只在f()中生效,所以第二个alert的值为1。
再结合上面的回答,就解决了。
另外,更改一个函数的值的方法是直接赋值,不加var


由于变量提升的原因,实际执行的代码相当于是

<script type="text/javascript">
        var str1="b";
        function test(){
            var str1;
            alert(str1); 
            str1 = "c";
        }
        test();
</script>

函数内部有定义变量名为str1的变量,这个时候他回覆盖函数外的同名变量,而且根据变量提升原理,在执行执行alert(str1)之前,str1只是在函数内部进行了定义,但并没有实际的赋值。所以输出也就是undifined了


参考这里的变量声明提升部分

【热门文章】
【热门文章】