前端基础进阶(四):详细图解作用域链与闭包

https://segmentfault.com/a/1190000012646488  https://yangbo5207.github.io/wutongluo/

说明:此处只是记录阅读前端基础进阶的理解和总结,如有需要请阅读上面的链接

一、作用域链

作用域链是由当前环境和当前环境以上的一系列变量对象组成的,它保证了有权限的变量对象的有序访问。这句话怎么理解,看下下面的例子

var a = 20;

function test() {
    var b = a + 10;

    function innerTest() {
        var c = 10;
        return b + c;
    }

    return innerTest();
}

test();

VO(global),VO(test), VO(innerTest)分别表示全局上下文,函数test的执行上下文,函数(innerTest)的执行上下文的变量对象,那么函数test的作用域链包括VO(test)、VO(global),而函数innerTest的作用域链则包括以上三个变量对象。

可以用一个数组来表示作用域链,当前环境的变量对象放在作用域链的前端,末端是全局上下文的变量对象。可以把作用域链理解为以最前端为起点,最末端为终点的单方向通道

innerTestEC = {
    VO: {...},  // 变量对象
    scopeChain: [VO(innerTest), VO(test), VO(global)], // 作用域链
}

二、闭包

如果子函数B中访问了父函数A中的变量,则形成闭包。大部分书籍以函数B指代闭包,如闭包B,而谷歌浏览器以函数A指代闭包。

闭包的存在使得原本应该在函数结束时释放的变量空间保存了下来,供子函数调用的时候使用。

// demo01
function foo() {
    var a = 20;
    var b = 30;

    function bar() {
        return a + b;
    }

    return bar;
}

var bar = foo();
bar();

如上函数bar访问了父函数foo中的变量a,b形成闭包,并且当foo函数执行完时,变量对象a,b并没有被释放,而是保存了下来供函数bar使用,正常情况下如果没有闭包变量对象a,b是应该释放的。

闭包只产生在只有父子关系的函数中吗,其实不是的,只要函数B访问了其以上的任何一个函数的变量对象,闭包都会产生,看如下例子

 function foo() {
            var a = 20;
            var b = 30;

            function bar() {
                return function dd() {
                    return a + b;
                }
            }

            return bar;
        }

        var bar = foo();
        var dd = bar();
        console.log(dd());

三、练习题

利用闭包,修改下面的代码,让循环输出的结果依次为1, 2, 3, 4, 5

for (var i=1; i<=5; i++) {
    setTimeout( function timer() {
        console.log(i);
    }, i*1000 );
}

这个题目需要了解setTimeout的详细用法和闭包的概念,详细答案https://mp.weixin.qq.com/s/XB6OS2b162fV8YQ-TzE_nQ

for (var i=1; i<=5; i++) {
    setTimeout( (function(i) {
        return function() {
            console.log(i);
        }
    })(i), i*1000 );
}

这里记一下为什么会用到自执行函数,用到自执行函数主要是为了保存i的值,利用传参把每次i的值保存在每一个自执行函数的参数中,然后利用闭包访问每次保存的值。需要注意的是setTimeout里面的函数中的i和for循环的i其实是两个不同对象,它是函数的参数保存着i的值,因此也可以像下面这样写

for (var i = 1; i <= 5; i++) {
            setTimeout((function (a) {

                return function () {
                    console.log(a);
                }
            })(i), i * 1000);
        }
原文地址:https://www.cnblogs.com/lidaying5/p/8476365.html