如何理解闭包?闭包的特性

9 篇文章 0 订阅

闭包

前言(你必须了解与之关联的知识)

提到闭包不得不提到,作用域链,更不得不提起词法作用域,学习闭包的时候总把自己搞得晕头转向?是不是觉得外部函数定义的局部变量在函数返回后就不存在了,之所以有这种想法,是因为我们忽略了作用域链的存在,晕头转向是因为我们忽略了词法作用域的特点。在Javascript并非函数执行结束后与之关联的作用域链就不存在了。

定义(通过了解了与之关联的知识来思考闭包的存在)

函数对象可以通过作用域链相互关联起来,函数体内的变量都可以保存在函数作用域内,这种特性在计算机科学文献中称为"闭包";

理解(知识串联)

粗略的理解,所有JavaScript函数都是闭包。我们知道函数都是对象,变量保存在函数的作用域内,函数对象通过作用域链关联了起来。嵌套函数可以访问到父函数定义的变量,词法作用域就是JS查找某个变量的规则,词法作用域规则而指出了函数作用域是在函数定义的时候就确定了,而非运行的时候;作用域链则是JS寻找某个变量的链条,如果找到链条的末端都没找到就会返回referenceError的错误。

案例

简单的案例

var scpoe = "global";
function fun1(){

    var scope = "local";
    return function (){
        console.log(scope)
    }
}
var fun = fun1();
fun()

在这里插入图片描述
fun1 返回一个function对象后看似乎fun1就运行结束,存放在fun1的变量,按道理是会消失的。但是看运行结果却以然能够被返回的这个function对象访问。而且控制台输出的是fun1函数内定义的变量,而非全局变量。
其实如果你知道词法作用域规则,和作用域链你就能明白闭包是什么了。
我们来看,每次调用JavaScript函数的时候,都会 为之创建一个新的对象用来保存局部变量,并且把这个对象保存到作用域链中,运行结束后如果这个函数没有被其他引用指向这个对象,它就会被当作垃圾回收,如果定义了嵌套函数,并且将它当作返回值返回那么存在一个变量存放了该函数对象引用,他就不会被当作垃圾回收,并且它所指向的变量绑定对象也不会被当作垃圾回收。所以闭包使用不当的话是会造成内存泄漏的。

简单的应用(JS绑定事件示例,加深认识)

没有使用闭包

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Tbounditle</title>
</head>
<body>
<input type="button" id="btn1" value="按钮1">
<input type="button" id="btn2" value="按钮2">
<input type="button" id="btn3" value="按钮3">
</body>
<style type="text/css"></style>
<script type="text/javascript">
    var buttons = document.getElementsByTagName("input")
    for (var i = 0; i<buttons.length; i++){
        buttons[i].addEventListener("click",function (){
            alert(i)
        })
    }
</script>
</html>

结果:每个按钮alert的都是3;
为什么呢?
绑定的时候是i的值0,1,2分别进行绑定的没错,但是这个方法最终是触发按钮的时候才调用了这个回调函数,对于这个函数所处的词法作用域上的值此时已经累加到3了;所以每次点击按钮只会读到3这个值;
使用了闭包

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Tbounditle</title>
</head>
<body>
<input type="button" id="btn1" value="按钮1">
<input type="button" id="btn2" value="按钮2">
<input type="button" id="btn3" value="按钮3">
</body>
<style type="text/css"></style>
<script type="text/javascript">
    var buttons = document.getElementsByTagName("input")
    for (var i = 0; i<buttons.length; i++){
        (function (i){
            buttons[i].addEventListener("click",function (){
                alert(i)
            })
        })(i)
    }
</script>
</html>

结果:每个按钮alert的分别是0,1,2
为什么不一样?
前面提到过的:每次调用JavaScript函数的时候,都会 为之创建一个新的对象用来保存局部变量;
我们通过自调用函数,然后把i传递给该函数,他就会在每次调用的到时候把这个i值保存一份到该函数作用域中(或者理解成闭包),循环了多少次就执行多少次函数,也就创建了多少个闭包,每个闭包都保存了相应的值,闭包的特性就是即使函数运行结束了,只要我有引用指向该返回的函数(这里指回调函数),那么等到事件触发的时候,他就会调用该函数,从而获取到闭包当时独立保存的变量。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jaywei.online

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值