JS深入之闭包

1,282 阅读4分钟

最近在复习ES6的知识点,又重新理解了闭包这个概念,发现自己之前的理解只是“浅尝即止”,今天有了新的理解,特地来总结一波。

首先我们从经典三问来看:是什么(what)?为什么(why)?怎么产生闭包(how)?

一、什么是闭包?

在 JavaScript 中,根据词法作用域的规则,内部函数总是可以访问其外部函数中声明的变量,当通过调用一个外部函数返回一个内部函数后,即使该外部函数已经执行结束了,但是内部函数引用外部函数的变量依然保存在内存中,我们就把这些变量的集合称为闭包。比如外部函数是 foo,那么这些变量的集合就称为 foo 函数的闭包。

那么总结出以下两点:

1、闭包是一个嵌套在函数里面的内部函数所产生的闭合的一个容器可以理解成一个对象(是以key:value的形存在的)。

2、闭包保存的是内部函数访问外部函数的变量,并且保存在内部函数当中。

二、怎么产生闭包(产生闭包的条件)?

根据前面第一点可以知道,产生闭包首先第一点需要函数嵌套,否则也无谈内部函数外部函数了。 其次,内部函数需要引用了外部函数的变量才能产生闭包

比如这段代码:

function fun() {
    var num = 123;
    // 函数嵌套
    function fun2() {
        // 内部函数引用外部函数的变量
        console.log(num);
    }
    fun2()
}
fun()

Image.png

从控制台可以看到,闭包是一个对象(键值对的形式),而且保存在嵌套的内部函数(fun2())当中,闭包的作用是保存外部函数的变量(在内部调用的变量)。

三、为什么要设计闭包

其实我们也知道,闭包可以保存函数的变量,那么其实也就是

1、可以延长局部变量的生命周期

2、可以从外部访问函数内部的局部变量

四、闭包的缺点

闭包也有缺点,比如闭包虽然延长了局部变量的生命周期,于此同时带来的也就是,长时间占用内存,这也会导致,如果不及时清除闭包容易使内存溢出。

那么如何避免闭包带来的缺点呢? 就是用完闭包之后及时的清除闭包。

五、闭包的使用场景

1、解决循环遍历加监听的问题。

不知道大家有没有遇到过这样的面试题:

for (var i = 0; i < btns.length; i++) {
    var btn = btns[i];
    // onclick是事件回调,所以不是立即执行,for循环直接执行。所以等点击的时候i已经变成3了
    // 简而言之:for循环是同步操作,而点击事件是异步操作。
    btn.onclick = function() {
        console.log(i); // 结果:不管点击哪个按钮,都是3
    }
}

这样的结果不管点击哪个按钮都是3,但我们的需求并不是这样的,所以我们可以利用闭包解决这个问题。 在onclick事件外嵌套一个立即执行函数,从而形成闭包。 👇

// 解决办法:用闭包解决,当立即执行函数执行完毕之后,作用域销毁,但是点击的时候仍然能够访问到变量i
// 也就是内部变量依然能够访问到
for (var i = 0; i < btns.length; i++) {
    var btn = btns[i];
    // 立即执行函数
    (function(i) {
        btn.onclick = function() {
            console.log(i); // 结果:点击一次执行一次
        }
    })(i)
}

2、将内部函数返回出来

function fun() {
    var num = 123;
    // 函数嵌套
    return function fun2() {
            // 内部函数引用外部函数的变量
            console.log(num);
        }
        // fun2()
}
// var 一个fun2来接收这个函数
var fun2 = fun()
console.log('----');
fun2(); // 结果:打印出123 ,也就是说在外部也能访问到函数里面本来应该被销毁的变量

3、自定义JS模块

我们可以通过闭包,自定义JS模块,然后在实际使用中可以通过模块暴露的对象,调用方法来实现对应的功能。

结语

最后我想说,其实我认为对于闭包,每个人有每个人不同的理解,也许会有些许的偏差,但是没有绝对的概念。因为每个人的知识体系不同,理解角度不同,思考方式也不同~~

所以我在网上参考资料的时候,是尽量转化成我所能理解并接受的知识,并分享出来,如有错误,欢迎大家批评指正~~