# 闭包

# 定义

  1. 如何产生闭包
    • 当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包
  2. 闭包到底是什么
    • 闭包是嵌套的内部函数
    • 包含被引用变量(函数)的对象
    • 闭包存在于嵌套的内部函数中
  3. 产生闭包的条件
    • 嵌套函数
    • 内部函数引用了外部函数的数据(变量/函数)
function fn1() {
    var a = 1
    function fn2() {
        console.log(a)
    }
}
fn1()
1
2
3
4
5
6
7

# 常见的闭包

  • 将函数作为另一个函数的返回值

    function fn1() {
        var a = 1
        function fn2() {
            a++
            console.log(a)
        }
        return fn2
    }
    var f = fn1()
    f() // 3
    f() // 4
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
  • 将函数作为实参传递给另一个函数调用

    function showDelay(msg, time) {
        setTimeout(function() {
            alert(msg)
        }, time)
    }
    showDelay('闭包', 2000)
    
    1
    2
    3
    4
    5
    6

# 作用

  1. 使用函数内部的变量在函数执行完后,仍然存活在内存中(延长了局部变量的生命周期)
  2. 让函数外部可以操作(读写)到函数内部的数据(变量/函数)

值得注意

  • 函数执行完后,函数内部声明的局部变量一般不存在,存在于闭包中的变量才可能存在
  • 在函数外部不能能直接访问函数内部的局部变量,但是可以通过闭包让外部操作它

# 生命周期

  • 在嵌套内部函数定义执行完时就产生了(不是在调用)

  • 在嵌套的内部函数成为垃圾对象时,就消失

    function fn1() {
        var a = 1 // 此时闭包已产生(函数提升,内部函数对象已经创建)
        function fn2() {
            a++
            console.log(a)
        }
        return fn2
    }
    var f = fn1() // 产生闭包
    f() // 3
    f() // 4
    f = null // 闭包消失,包含闭包的函数对象成为垃圾对象
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

# 应用

  • 定义 js模块

    // myModule.js
    function myModule() {
        // 私有的变量数据
        var msg = 'my module'
        function do() {
            console.log('do' + msg)
        }
        function other() {
            console.log('other' + msg)
        }
        // 向外暴露对象或方法
        return {
            do: do,
            other: other
        }
    }
    
    // main
    var m = myModule()
    m.do()
    m.other()
    
    // myModule2.js
    (function(w) {
        var msg = 'my module'
        function do() {
            console.log('do' + msg)
        }
        function other() {
            console.log('other' + msg)
        }
        // 向外暴露对象或方法
        w.myModules = {
            do: do,
            other: other
        } 
    })(window)
    
    // main 更优化的方法,可直接引用使用
    myModules.do()
    myModules.other()
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42

# 闭包的缺点

  • 函数执行完成后,函数内的局部变量没有释放,占用内存时间会变长
  • 容易造成内存泄漏

怎么解决

  • 能不用就不用
  • 及时释放

# 内存溢出和内存泄漏

内存溢出

  • 一种程序运行出现的错误
  • 当程序运行需要的内存超过了剩余的内存时,就抛出内存溢出的错误

内存泄漏

  • 占用的内存没有及时释放
  • 内存泄漏积累多了就容易导致内存溢出
  • 常见的内存泄漏
    • 意外的全局变量
    • 没有及时清理的计时器或回调函数
    • 闭包
更新于: 1/28/2020, 10:52:04 AM