浅谈JS闭包

470 阅读2分钟

时隔一年重新回过头来看JavaScript中的相关核心概念,闭包始终是一个不管是面试还是技术交流的时候都无法避免的一个老生常谈的话题。我记得差不多4年前开始接触前端的时候,总会被闭包这个概念给搞迷糊,每次阅读闭包相关的文章的时候,看完后觉得自己懂了,后来每当被别人问起“什么是闭包“的时候,给出的解释连自己都不能够被说服。 似懂非懂。相信有一些同学和我有同样的感受,这边文章里面咱们就简单的交流一下什么是闭包。 

WHAT 是闭包

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.

简单来说,闭包是由函数以及声明该函数的词法环境组合而成的。 该环境包含了这个闭包创建时作用域的任何局部变量。闭包是一个组合,它包含了函数和围绕该函数的词法环境

举个例子,下面的例子中最终的输出结果是什么呢? 

for( var i = 0; i < 3; i++ ) {
    setTimeout(() => {
        console.log( i );
    }, 1000)
}

这个问题相信很多人都知道答案,结果是并不是 0 1 2 而是  3 3 3

上面的代码如何调整才能达到我们期望的输出呢,答案是创建相互独立的闭包,换句话就是更改并重新构建一个围绕setTimeout 函数的作用域/词法环境。 下面我简单介绍两种方式来达到上面的目的。 

//方法一 
for(var i = 0; i < 3; i ++){
    (function(j){
        setTimeout(()=>{
            console.log(j)
        },1000)
    })(i)
}

//方法二 es6
for(let i = 0; i < 3; i ++){
    setTimeout(()=>{
        console.log(i)
    },1000)
}

经典测试题 

function fun(n, o) {
    console.log(o);
    return {
        fun: function(m) {
            return fun(m, n);
        }
    };
}

// var a = fun(0); a.fun(1);  a.fun(2); a.fun(3);  // 输出 ???  
// var b = fun(0).fun(1).fun(2).fun(3)  // 输出 ??? 
// var c = fun(0).fun(1); c.fun(2); c.fun(3); // 输出 ??? 

正确答案

// 第一行  undefined 0 0 0 
// 第二行  undefined 0 1 2
// 第三行  undefined 0 1 1

总结

闭包无处不在,javascript 是function-first的面向对象语言,如何正确的理解并分析当前函数的词法环境 or 作用域Scope是理解闭包的关键。

希望各位童鞋,可以多给一些反馈。如果觉得这篇文章还不错的话,麻烦给一个赞谢谢😄 happy coding.