JS闭包总结


目录给这呢

  • JS闭包总结
  • 定义
  • 用debuuger观察闭包
  • 闭包的作用
  • 延长变量的生命周期
  • 闭包的经典应用
  • 经典应用1实现节流函数
  • 让函数只能被调用指定次数
  • 经典应用3
  • 闭包与内存泄漏


定义

定义
在A函数中定义一个B函数(函数的嵌套定义),在B函数中使用了A函数中的变量,就会产生闭包。具体来说,就是B就是一个闭包。

闭包的三大特点为:

1函数嵌套函数
 内部函数可以访问外部函数的变量
 参数和变量不会被回收。

注意:
1.嵌套定义
2.引用变量

用debuuger观察闭包

下面这个简单的js函数里就构成啦闭包

go func 闭包 参数_生命周期


我们来利用调试器看看闭包的产生

go func 闭包 参数_嵌套_02


go func 闭包 参数_生命周期_03


如果没有变量引用,则也不会看到闭包。

闭包的作用

何时使用

变量既想反复使用,又想避免全局污染

如何使用?

定义外层函数,封装被保护的局部变量。
 定义内层函数,执行对外部函数变量的操作。
 外层函数返回内层函数的对象,并且外层函数被调用,结果保存在一个全局的变量中。

1 延长变量生命周期。

go func 闭包 参数_go func 闭包 参数_04


上面的代码中,闭包B会延长变量i的生命周期,它有能力可以让i活的更久一些。这里的i 是A的局部变量,它正常的生命周期是函数A的调用过程。

go func 闭包 参数_生命周期_05

在调用A的过程中,由于i是它的局部变量,所以A会向内存申请一个空间来放i,但当A调用结束后,这个空间会回收,即i就死了。
    
   闭包B的能力就是可以让函数A()执行完成之后,i仍然活着!!!!实现这个能力还需要有一个帮手:return !

延长变量的生命周期

go func 闭包 参数_生命周期_06

可以看到,每次调用r(),都可以对i的值进行++,再输出来。这就说明,A()调用之后,i 并没有死掉了,它还活着。

原因如下

还没有开始调用A()

go func 闭包 参数_生命周期_07

接下来,开始调用A()A函数内部,有两个局部变量:B 它还是引用类型的。要用到堆区所以A会去申请空间

go func 闭包 参数_go func 闭包 参数_08

接下来,执行return B

go func 闭包 参数_局部变量_09

结果如下:

go func 闭包 参数_go func 闭包 参数_10

由于在B的函数体中用到变量i ,所以i的空间不能被回收。即i的生命周期被延长了。

再次观察调试面板:

go func 闭包 参数_js_11


由于在函数B的内部它用到它外部的变量i,在这个函数B没有死掉之前,i是不会消失的。

闭包的经典应用

经典应用1实现节流函数

在mui的buffer()函数中,我们提到了节流函数。节流函数就是一个函数在指定的时间间隔内,只能被调用一次。

例如,f函数,在1000ms内,只能调用一次。换句话,此时你调用f,则下一次再调用要等1000ms。本质上就降低函数执行的频率。

go func 闭包 参数_生命周期_12


go func 闭包 参数_局部变量_13


要求:1000ms内只能执行一次f.

改进如下:

go func 闭包 参数_局部变量_14


go func 闭包 参数_生命周期_15

上面的代码起到了降频的效果。

分析:

go func 闭包 参数_嵌套_16

Var f = A():执行完成,

下面执行
Div.addEventListenter(“mousemove” ,f)
这一句执行之后,则如果鼠标在div上移动就会去调用f,

分析一下调用f的过程。

下面的代码就是f的函数体:

go func 闭包 参数_嵌套_17

比较当前的时间与第一次保存的now的值之间是否>500( 表示时间过了500ms ).如果成立,则执行核心语句: Console.info(“鼠标移动中…”)

同时更新最近一次执行f的时间。Now = Date.now(); 由于now没有回收,所以它还可以正常访问的。

如果不成立(说明时间没有过500ms)

下面是一个节流函数

go func 闭包 参数_go func 闭包 参数_18

让函数只能被调用指定次数

go func 闭包 参数_嵌套_19

go func 闭包 参数_go func 闭包 参数_20

经典应用3

go func 闭包 参数_go func 闭包 参数_21


上面点击每一个li都会输出3

解决办法 1:使用自定义属性

go func 闭包 参数_嵌套_22


解决办法 2:使用闭包

go func 闭包 参数_局部变量_23

(1)iife。在function的前面有=号。
lis[i].onclick = function(index){}(i)

(2)闭包结构。

a)	function的嵌套
b)	在子函数中,用到了index,而index是父函数的形参,就相当于是父数的局部变量。所以 ,也就是在子函数中使用了父函数中定义的变量。
c)	Return 子函数。

闭包与内存泄漏

一般来说,在函数内部定义的变量,会随着函数的调用结束而被系统回收,如下:
Function f(){
Var i ;
}
F();
在F()执行完成后,i就不能再访问到了 。

由于闭包结构的存在,如下:

Function f(){
 Var i ;
 Return function(){
  Console.info( i):
}
}

Var r = f();
R();

上面的代码中,由于r()在执行时,还需要用到变量i,这个变量i并不会被系统回收。