12.闭包

一、背景

实现点击某个按钮,提示点击的是第几个按钮

var btns=document.getElementsByTagName('btn');
for(var i=0,length=btns.length;i<length;i++){
    var btn=btns[i];
    btn.onclick=function(){
        alert('第'+(i+1)+'个')
    }
}
console.log(i);
//在函数未被触发时,全局中的i值为3,点击之后函数从全局中找i值,此时的i值为3。


二、闭包

1.闭包出现的时机:

闭包是在内部函数定义的时候出现。下面这个例子中当执行fn1()函数后,在进行预处理的时候就对函数fn2进行了定义,所以此时形成了闭包。

但如果fn2函数写成了表达式的形式,在刚运行fn1函数的时候就不会产生闭包。因为我们之前说过函数表达式不会进行预处理(及函数提升)。

function fn1(){
    var a=2;
    var b='abc';
    //函数定一个就会产生闭包(不用调用内部函数)
    function fn2(){
        console.log(a);
    }
}
fn1();

2.根据上面的代码样例来解释什么是闭包:

首先从形式上来看,闭包就是函数嵌套的,且内部函数调用了外部函数的变量。但是从本质上看,内部函数调用了外部函数的变量,所以在内部函数中存在这对外部函数的一个引用,虽然数据不是一个对象类型,但是变量是一个引用类型的变量。

正常来说,一个函数执行完毕,其上下文对象会被立即 销毁,但是由于闭包的存在(闭包对外部函数还有引用),所以无法销毁该函数上下文对象。

三、常见的闭包

  • 将函数作为另一个函数的返回值
function fn1(){
            var a=2;
            function fn2(){
                a++;
                console.log(a);
            }
            return fn2;
        }
        var f=fn1();
        f();		//3
        f();		//4

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dh7qFdqT-1619089744656)(C:\Users\86185\AppData\Roaming\Typora\typora-user-images\image-20210329212931386.png)]

一定要牢记 上面这个图,这图吊打一切讲解闭包的说法。

  • 将函数作为实参传给另一个函数调用

四、闭包的作用

1.使用函数内部的变量在函数执行完后,仍然存活在内存中(延长了局部变量的声明周期)。

2.让函数外部可以操作(读写)到函数内部的数据(变量/函数)。

对闭包的认识:

我觉得闭包的出发点是为了防止污染全局作用域。

那么要实现防止污染全局作用域,那只能写在一个函数作用域中了,可是,设计师又觉得,放在函数作用域中我得操作里面的数据呀,是的,这时候有人就会说,我把所有的数据和操作都放在一个函数中,然后再外部调用这个函数,既可以避免防止全局作用域,又可以对数据进行操作,最后我们数据返回就ok了。

可是我现在要做的是对函数内部数据的多次操作,且每次操作都是对上一次操作的持续操作,显然,这时候使用一个函数是不行的,因为每次操作都伴随着对数据的重新定义和使用。那么怎么做到我每次操作的时候是对上一次操作的持续而不是重复呢?

好的,闭包的作用就来了,我们上面说过,闭包是再外部函数嵌套一个内部函数,内部函数调用外部函数的数据。这时候我们执行完外部函数,本该是所有内部的所有局部变量数据被销毁的,但是因为存在着对外部函数的引用,所以该数据就不会被销毁。所以这时候我们就可以通过多次的执行内部函数,从而实现我们前面所说的,每次函数调用都是对上一次函数操作的持续。这也就是我们上面所说的,为什么闭包如果不被返回return出来是没有意义的。

因为一旦闭包没有被引用,那么就会再垃圾回收的时候被回收。被回收了,自然就实现不了我们之前所说的多次函数调用,实现对数据的持续操作。

五、闭包的声明周期

产生:在嵌套内部函数定义执行完时就产生了(不是在调用闭包的时候出现);

死亡:在嵌套的内部函数称为垃圾对象时;

六、利用闭包实现js模块化

 //js中使用闭包实现模块思想  这里实现了es6和node.js中同样的模块思想,这时候当使用script或者是es6中的import方式导入的时候,该模块中的所有变量都是在一个函数作用域中的,避免了变量干扰
 (function(window){
    var msg="my name";
    function doSomething(){
        console.log('doSomething'+msg.toUpperCase())
    }
    function doOtherthing(){
        console.log('doOtherthing'+msg.toLowerCase());
    }
    //向外暴露多个函数则写成对象的形式暴露出去
    window.myModule2={
        doSomething:doSomething,
        doOtherthing:doOtherthing
    }
   }
   )(window)

七、闭包的缺点

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

2.解决:

  • 能不用闭包就不用
  • 及时释放。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值