【JavaScript】闭包

1.对闭包的理解

先看案例

function Func() {
    let count = 0

    return function () {
        return count++
    }
}

var Func_1 = Func()
console.log(Func_1()); //1
console.log(Func_1()); //2
console.log(Func_1()); //3

代码分析

从代码中我们可以看到,Func函数返回的是一个匿名函数,在该匿名函数中,访问到当前函数的局部变量count,并执行了处理,形成闭包

Func_1Func的实例,指向的是Func返回的匿名函数。

当第一次执行Func_1()的时候,返回1,此时count变量在该函数中并没有被销毁,而是被存储下来

那么第二次和第三次调用的时候,count变量仍然能够访问当上次修改后的结果,并可以做出修改,使变量私有化

定义

闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,创建的函数可以访问到当前函数的局部变量。

简单来说:就是在一个执行上下文中创建的函数,如果访问了这个执行上下文中变量对象的值,那么闭包就产生了

2.闭包解决的问题

我们都知道,根据作用域查找规则,外部是不能访问到函数内部数据,如果我们想访问函数内部数据,可以借助函数中的return

function f1(){
    var num = 10;
    return num;
}
var res = f1();
console.log(res); // 10

借助return可以访问到函数内部数据,但存在一个问题:数据不能被二次访问。因为第二次访问时候是再次调用该函数,函数中的代码才会再次返回,这个我们通过生成随机数可以很好的证明:

function f1() {
  var num = Math.random();
  return num;
}
var res1 = f1();
var res2 = f1();
console.log(res1 + '\n' + res2);

输出结果如下,我们发现两次的输出结果并不一样:

image-20230806221827393

无论我们怎样执行,两次的随机数结果都不同,这种输出结果显然不好。如果我们想让函数只执行一次,我们该怎么做呢?我们可以f1函数中嵌套一个函数,嵌套的内部函数是可以访问f1函数变量的。

function f1(){
  var num = Math.random();
  
  function f2(){
    return num 
  }
  
  return f2
}

var f = f1();
var res1 = f();
var res2 = f();
console.log(res1 + '\n' + res2);

此时的输出结果如下:

image-20230806221633261

这就产生了闭包,我们试着分析一下这段代码:

  • 全局f1函数在0级作用域链上,f1函数是一个一级链,f1函数中有一个变量num,还有一个函数体f2
  • f2是二级链,通过return将f2当做一个值返回给f1函数。
  • f1函数执行后,将f2的引用赋值给f,执行f函数,输出num变量。

正常来说,当f1函数调用完毕,其作用域是被销毁的,而通过闭包我们将f2给了ff2函数内仍然持对num的引用,num仍然存活内存中,延长了内部函数局部变量生命周期。在当f调用,num是可以访问到的。

image-20230806221546937

其实,闭包也就是使用了链式访问技巧,0级链无法访问一级链数据,我们通过间接0级链操作二级链的函数,来访问一级链数据。

闭包解决的问题是:让函数外部访问到函数内部的数据。

3.闭包本质

看下面这段代码,我们来分析闭包是如何产生的:

image-20230806222416875

分析:每个函数的内部都会有一个[[Scopes]],用来存储作用域中的变量,其中包括Global全局变量和自身上下文中的局部变量,一旦闭包产生,生成一个Closure的对象来存储 调用父元素的变量

4.闭包的缺点

闭包也存在着一个潜在的问题,由于闭包会引用外部函数的变量,但是这些变量在外部函数执行完毕后没有被释放,那么这些变量会一直存在于内存中,总的内存大小不变,但是可用内存空间变小了。 一旦形成闭包,只有在页面关闭后,闭包占用的内存才会被回收,这就造成了所谓的内存泄漏。

因此我们在使用闭包时需要特别注意内存泄漏的问题,可以用以下两种方法解决内存泄露问题:

  • 及时释放闭包:手动调用闭包函数,并将其返回值赋值为null,这样可以让闭包中的变量及时被垃圾回收器回收。
  • 使用立即执行函数:在创建闭包时,将需要保留的变量传递给一个立即执行函数,并将这些变量作为参数传递给闭包函数,这样可以保留所需的变量,而不会导致其他变量的内存泄漏。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值