美文网首页饥人谷技术博客
JS作用域链和声明前置的理解

JS作用域链和声明前置的理解

作者: 老虎爱吃母鸡 | 来源:发表于2016-07-21 14:30 被阅读0次

    例题:

        var a = 1;
        function fn() {
            var a 
            console.log('1.'+a);//undefined
            a = 5;
            console.log('2.'+a);//5
            function fn2() {
                console.log('3.'+a);//6
                a = 20;
            }
            a++;
            fn2();
            console.log('4.'+a);//20
        }
        fn();
        console.log('5.'+a);//1
    

    例题中的作用域链:

            //全局作用域下的变量对象
        window.scope={
            a://var a = 1的时候是1,a = 10的时候为10,
            fn:function () {
                ...
            }
        }
        //fn()作用域下的变量对象
        1.fn.scope={
            a://声明的时候是undefined,a = 5的时候是5,a++的时候是6,fn2()中a = 20赋值过后是20,
            fn2:function () {
                ...
            }
        }
        2.window.scope={
            a:1,
            fn:function () {
                ...
            }
        }
        //fn2()作用域下的变量对象
        1.fn2.scope={}
        2.fn.scope={
            a://声明的时候是undefined,a = 5的时候是5,a++的时候是6,fn2()中a = 20赋值过后是20
            fn2:function () {
                ...
            }
        }
        3.window.scope={
            a:1,
            fn:function () {
                ...
            }
        }
    

    console.log('1.'+a):在JS中的语句var a = 1其实是两条语句var aa = 1的合并,其中语句var a由于声明前置会被提到作用域的开头,例如:

    console.log(a);
    var a = 1;
    

    这个console.log(a)会输出undefined。


    console.log('2.'+a):在fn()的作用域中,a已经被声明过,所以a = 5就直接将5赋值给a。


    console.log('3.'+a):为什么会输出6呢,因为:

    1. 在进入fn2()的执行环境之前,有一个a++
    2. fn2()的作用域中没有声明a,在调用a这个变量的时候就会顺着作用域链往外层查找,在fn()的作用域中找到了已经被声明的a

    console.log('4.'+a):不是说好的外层作用域不能访问内层吗,可是为什么fn2()中的a = 20会影响到fn()里的a呢?因为:

    • fn2()中的a = 20改变的本来就是fn()中声明过的a的值

    console.log('5.'+a):在fn2()中a = 20没有var关键字,不是说在函数内没有使用var关键字直接给变量赋值会成为全局变量吗,这里的console.log输出不应该是20吗,为什么还是1呢?

    1. 首先我们看看为什么函数内没有加var关键字的变量会变成全局变量呢?
      例如:

       function fn() {
           b = 1;
       }
       fn();
      

      我们都知道,在全局作用域下的变量和函数都是window对象的属性和方法。其实在fn()被调用的时候,b = 1顺着作用域链想找到被声明的b赋值,但是无论fn()的作用域还是全局作用域都没声明b,所以解析器就做了window.b=1这样一个行为,就是给window对象加了一个b:1的名值对。

    2. 然后为什么fn2()的a = 20没有加到全局对象上呢?
      因为fn2()顺着作用域链查找的时候在fn()的作用域中找到了已经被声明过的a,所以20就直接赋值给了fn()中已经声明过的a。


    相关文章

      网友评论

        本文标题:JS作用域链和声明前置的理解

        本文链接:https://www.haomeiwen.com/subject/rfubjttx.html