理解闭包

背景:javascript中没有块级作用域的概念,只有函数拥有作用域。

在下面的例子里,要实现累加,counter必须定义在autoadd函数之外,作为一个全局变量

var counter=1;
function autoadd(){
    counter++;
    console.log(counter);
}

在上面这个累加函数中,变量counter仅仅作为一个计数器存在,定义为全局变量没有必要。并且在多人开发的项目上,过多的全局变量容易产生冲突。

为了解决这个问题,利用作用域链的特性可以模仿一个私有作用域,用匿名函数作为一个“容器”,“容器”内部可以访问外部的变量,而外部环境不能访问“容器”内部的变量,这就是闭包

function wrapper(){
    var a=1;
    function autoadd(){
        a++;
        console.log(a);
    }
}
wrapper();

但autoadd在wrapper中只是一个函数声明,我们并不能访问到。为了使我们能访问的真正需要的函数,我们可以将这个函数返回

var x=(function(){
        var a=1;
        return function(){
            a++;
            console.log(a);
        }
})();
x();//2
x();//3
x=null;//解除引用,等待垃圾回收

总结一下闭包的作用:使当前作用域总能访问外部作用域中的变量。由此可以说,只要是内部函数引用了外层包裹函数中的变量则形成了一个闭包。而返回内层函数只是闭包为了取得内层函数的一种常见形式,并不是必要条件,不要混淆概念!

闭包与分组操作符()
  var f = function() {
    var num = 0;
    return function() {
      return num += 1;
    };
  }
f()()  // 1
f()()  // 1
var fn = f();
fn()
// 1
fn()
// 2
fn = null //解除引用

在这里f()表示执行f所引用的函数,即外层函数,返回内层函数,但此时内层函数还并未执行。在f()后再加一个分组符,表示执行f()所引用的函数,即内层函数。然而为什么不论执行多少次f()()结果都是1,而写成var fn = f();就可以呢?因为第一种写法外部对内层函数并没有引用,在执行完之后其内存就被回收了。而在第二种写法中,fn是对内层函数的引用,只要fn不被解除引用,计数器num就不会被销毁

闭包与内存

为什么在第一个例子中counter必须写在累加函数外才能实现功能?

如果写在函数内,因为autoadd在执行完后,counter再也没有被其他地方引用,于是内存被回收了,它的生命周期只在累加函数中。而在第一个例子中,由于counter是全局变量,只有在关闭浏览器之后才会被回收,所以才能实现累加的功能。

在使用闭包的例子中,因为a被内层函数引用,而x通过外层函数的return引用到了内层函数。因此,只要x一直引用内层函数,a就不会被销毁。

var x=(function(){
        var a=1;
        return function(){
            a++;
            console.log(a);
        }
})();
x();//2
x();//3
x=null;//解除引用,等待垃圾回收

这样也带了新的问题,内存泄漏。如果在代码中使用了大量闭包,而使用结束后不消除引用,闭包就会一直存在内存当中,当超过了内存的存储量之后就会造成内存泄漏。因此闭包在使用完之后一定要解除引用

闭包的优缺点

优点:
1)使变量驻留在内存中(多了变缺点);
2)避免全局变量污染;
3)私有化变量;
缺点:
1)因为闭包会携带包含它的函数的作用域,所以比其他函数占用更多内存;
2)使用不当会造成内存泄漏;

闭包的应用

文章的后半段


参考博文:
https://www.cnblogs.com/libin-1/p/6384055.html
https://segmentfault.com/a/1190000012872694

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值