闭包

210315

1、引入
var btns = document.getElementsByTagName("button")
for(var i = 0,length = btns.length; i<length; i++){
    var btn = btns[i]
    //将btn所对应的下标保存在btn上 
    btn.index = i
    btn.onclick = function(){
        alert('第'+(this.index+1)+'个')
    }
}

//利用闭包
for(var i = 0,length = btns.length; i<length; i++){
    (function (i){//局部变量i
        var btn = btns[i] //局部变量i
        btn.onclick = function(){
            alert('第'+(i+1)+'个')
        }
    })(i)//读全局变量i
} 
2、理解闭包
  1. 如何产生闭包?

    • 当一个嵌套函数的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包
    function fn1(){
        var a = 2  //Local中的Scopes的Closure
        var b ='abc'
        function fn2(){ //执行函数定义就会产生闭包(不用调用内部函数)
            console.log(a)
        }
        fn2()
    }
    fn1()
    
  2. 闭包到底是什么

    • 使用chrome调试查看(Local中的fn2:Scopes的Closure)

    • 理解1:闭包是嵌套的内部函数

    • 理解2:包含被引用变量(函数)的对象

    • 注意:闭包存在于嵌套的内部函数中

  3. 产生闭包的条件

    • 函数嵌套
    • 内部函数引用了外部函数的数据
3、常见的闭包
  1. 将函数作为另一个函数的返回值

  2. 将函数作为实参传递给另外一个函数调用

    //产生几个闭包,看外部函数调用的次数
    //将内部函数作为外部函数的返回值,此函数产生了一个闭包
    function fn1(){
        var a = 2  //设断点
        function fn2(){
            a++  //设断点
            console.log(a)
        }
        return fn2
    }
    var f = fn1()
    f() //3
    f() //4
    
    function showDelay(msg,time){
        setTimeout(function(){
            alert(msg)
        },time)
    }
    showDelay('nidjis',2000)
    
4、闭包的作用
  1. 使函数内部的变量在函数执行完后,仍然存活在内存中(延长了局部变量的生命周期)
  2. 让函数外部可以操作(读写)到函数内部的数据(变量/函数)
  3. 函数执行完后,函数内部声明的局部变量是否还存在?一般不存在,存在于闭包中的变量可能存在
  4. 在函数外部能直接访问函数内部的局部变量吗? 不能,但是通过闭包可以让外部操作内部变量
function fn1(){
    var a = 2  //设断点
    function fn2(){
        a++  //设断点
        console.log(a)
    }
    function fn3(){
        a--
        console.log(a)
    }
    return fn3
}
/*如果没有变量保存fn1函数返回的函数,即执行完fn1后,fn3被释放,因为没有引用*/
var f = fn1()
f() //1
f() //0
5、闭包的生命周期
  1. 产生:在嵌套内部函数定义执行(创建函数对象)完时就产生了(不是在调用)
  2. 死亡:在嵌套的内部函数成为垃圾对象时
function fn1(){
	//此时闭包已经产生,因为函数提升,内部函数对象已经创建了
    var a = 2
    function fn2(){
        a++
        console.log(a)
    }
    return fn2
}
var f = fn1()
f() //3
f() //4
f = null //闭包死亡(包含闭包的函数对象成为垃圾对象)

function fn1(){
    var a = 2
    //此时闭包已经产生,(定义执行完后)
    var fn2 = function (){
        a++
        console.log(a)
    }
    return fn2
}
var f = fn1()
f() //3
f() //4
f = null //闭包死亡(包含闭包的函数对象成为垃圾对象)
6、闭包的应用_自定义js模块
  1. 具有特定功能的js文件
  2. 将所有的数据和功能都封装在一个函数内部(私有的)
  3. 只向外暴露一个包含n个方法的对象或函数
  4. 模块的使用,只能通过模块提供暴露的对象调用方法来实现对应的功能
//1、
function myModule(){
    //私有数据
    var msg = 'Hello'
    //操作数据的函数
    function doSomething(){
        console.log('doSomething():' +msg.toUpperCase())
    }
    function doOtherthing(){
        console.log('doOtherthing():' +msg.toLowerCase())
    }
    //向外暴露对象(给外部使用的方法)
    return{
        doSomething:doSomething,
        doOtherthing:doOtherthing
    }
}
var module = myModule()
module.doSomething()
module.doOtherthing()

//2、
(function(window){
     //私有数据
    var msg = 'Hello'
    //操作数据的函数
    function doSomething(){
        console.log('doSomething():' +msg.toUpperCase())
    }
    function doOtherthing(){
        console.log('doOtherthing():' +msg.toLowerCase())
    }
    //把向外暴露的东西,保存在window对象中
    window.myModule2 = {
        doSomething:doSomething,
        doOtherthing:doOtherthing
    }
})(window)  //两个小括号中的window,为了方便代码压缩
myModule2.doSomething()
myModule2.doOtherthing()
7、闭包的缺点及解决
  1. 缺点
    • 函数执行完后,函数内的局部变量没有释放,占用内存时间会变长
    • 容易造成内存泄漏
  2. 解决
    • 能不用闭包就不用
    • 及时释放 赋值为null
function fn(){
    var arr = new Array[100000]
    function fn2(){
        console.log(arr.length)
    }
    return fn2
}
var f = fn1()
f()

f = null //让内部函数成为垃圾对象--回收闭包
8、内存溢出与内存泄漏
  1. 内存溢出

    • 一种程序运行出现的错误
    • 当程序运行的内存超过了剩余的内存时,就会抛出内存溢出的错误
    var obj = {}
    for(var i = 0; i < 10000; i++){
        obj[i] = new Array(100000000)
    }
    
  2. 内存泄漏

    • 占用的内存没有及时释放
    • 内存泄漏积累多了就容易导致内存溢出
    • 意外的全局变量
    • 没有及时清理的计时器或回调函数
    • 闭包
    //意外的全局变量,用var声明变量
    function fn(){
        //var a = new Array(10000000)
        a = new Array(10000000)
        console.log(a)
    }
    fn()
    
    var interval = setInterval(function(){//启动循环定时器后不清理
        console.log('------')
    },1000)
    //clearInterval(interval)
    
    //闭包
    function fn1(){
        var a = 4
        function fn2(){
            console.log(++a)
        }
        return fn2
    }
    var f = fn1()
    f()
    //f = null
    
9、闭包相关代码
var name = "The Window"
var object = {
    name : "My Object",
    getNameFunc : function(){
        return function(){
            return this.name
        }
    }
}
alert(object.getNameFunc()()); //The Window


//闭包
var name = "The Window"
var object = {
    name : "My Object",
    getNameFunc : function(){
        var that = this
        return function(){
            return that.name
        }
    }
}
alert(object.getNameFunc()())  //My Object
function fun(n,o){
    console.log(o)
    return{
        fun:function(m){
            return fun(m,n)
        }
    }
}
var a = fun(0) 
console.log(a,a.fun(1), a.fun(2),a.fun(3))//undefined,0,0,0 a.fun()执行了外部a函数,创建了新的闭包,但没有值保存,产生的闭包立马消失,o一直为0
var b = fun(0).fun(1).fun(2).fun(3)//undefined,0,1,2
console.log(b)
var c = fun(0).fun(1)
console.log(c, c.fun(2), c.fun(3))//undefined,0,1,1
posted @ 2021-07-14 14:51  STRIVE-PHY  阅读(72)  评论(0编辑  收藏  举报