Skip to content

一、理解闭包

  1. 闭包如何产生
    • 当一个嵌套的内部函数引用了嵌套的外部函数的变量时,就产生了闭包。
  2. 闭包是什么
    • 闭包是嵌套的内部函数
    • 包含被引用变量的对象,闭包存在于嵌套的内部函数中。
  3. 闭包产生的条件
    • 嵌套函数
    • 内部函数引用外部函数的数据
    • 示例:
      javascript
      function fn1 () {
          var b = '123'
          var a = 2
          function fn2 () {
              console.log(a)
          }
          fn2();
      }
      fn1();

二、常见的闭包

  1. 将函数作为另一个函数返回值
    JavaScript
    function fn1 () {
        var a = 2
        function fn2 () {
            a++
            console.log(a)
        }
        return fn2
    }
    var f = fn1()
    f()
    f()
  2. 将函数作为实参传递给另一个函数调用
    JavaScript
    function showDelay(msg,time){
        setTimeout(function (){
            alert(msg)
        },time)
    }
    showDelay('1231232',2000)

三、闭包的作用

1. 函数内部的变量,在函数执行结束后,仍然存活在内存中,延长了局部变量的声明周期
2. 让函数外部可以操作到函数内部的数据(变量/函数)

四、闭包的生命周期

  1. 产生:在嵌套内部函数定义执行完成时产生(不是在调用产生)
  2. 死亡:在嵌套的内部函数成为垃圾对象时,闭包死亡,释放占用的内存。
    js
    function fn1 () {
        // 此时闭包产生了(函数提升,内部函数对象已经创建了)
        var a = 2
        function fn2 () {
            a++
            console.log(a)
        }
        return fn2
    }
    var f = fn1()
    f() //
    f() //
    f = null // 闭包死亡(包含闭包的函数对象,成为了垃圾对象)

五、闭包的应用:自定义js模块

具有特定的js文件,将所有的数据和功能封装在一个函数内部(私有的),值向外暴露一个包含n个对象或者函数,模块的使用者,只需要通过模块暴露的对象调用方法来实现对应功能。

  • 示例
js
<body>
    <script src='myModule.js'></script>
    <script>
        var module = myModule();
        module.doSomething();
        module.doOtherIng();
    </script>
</body>
js
function myModule() {
    // 私有数据
    var msg = 'Soul Mate'
    // 操作数据的函数
    function doSomething() {
        console.log('do something', msg.toUpperCase())
    }
    function doOtherIng() {
        console.log('doOtherIng'+msg.toLowerCase())
    }

    // 向外暴露对象(给外部使用的方法)
    return {
        doSomething: doSomething,
        doOtherIng: doOtherIng
    }
}
  • 另一种写法
js
<body>
    <script src="myModule2.js"></script>
    <script>
        myModule2.doSomething();
        myModule2.doOtherthing();
    </script>
</body>
js
(function myModule(window) {
    // 私有数据
    var msg = 'Soul Mate'
    // 操作数据的函数
    function doSomething() {
        console.log('do something', msg.toUpperCase())
    }
    function doOtherIng() {
        console.log('doOtherIng'+msg.toLowerCase())
    }

    // 向外暴露对象(给外部使用的方法)
    window.myModule2 = {
        doSomething: doSomething,
        doOtherIng: doOtherIng
    }
})(window)

六、闭包的缺点及解决

  • 缺点:函数执行后,函数内的局部变量没有释放,占用内存时间边长,容易造成内存泄漏
  • 解决:及时释放。变成垃圾对象进行释放
js
function fn1(){
    var arr = new Array[10000]
    function fn2(){
        console.log(arr.length)
    }
    return fn2
}
var f = fn1();
f();
f = null;//让内部函数成为垃圾对象,从而回收闭包对象

七、内存溢出和内存泄漏

  1. 内存溢出:一种程序运行错误,当程序运行时,需要的内存超过了剩余内存,就会抛出内存溢出的错误。
  2. 内存泄漏:占用内存没有及时释放,内存泄漏积累多了就容易造成内存溢出。
  3. 常见的内存泄漏:1.意外的全局变量。2.没有及时清理的计时器或回调函数。3.闭包
js
// 内存泄漏
// 意外的全局变量
function fn() {
    a = 3
    console.log(a);
}
fn();

// 没有及时清理的计时器或回调函数
var intervalId = setInterval(function () {//自动循环定时器不清理
    console.log('12312312312')
},1000)
clearInterval(intervalId)

八、小练习

js
var name = 'soul mate';
var object = {
    name:'my object',
    getNameFunc : function () {
        return function () {
            return this.name;
        }
    }
}
alert(object.getNameFunc()());//soul mate

var name2 = 'the window'
var object2 = {
    name2:'my Object',
    getNameFunc: function(){
        var that = this;
        return function(){
            return that.name2
        }
    }
}
alert(object2.getNameFunc()())//my object

Released under the MIT License.