请选择 进入手机版 | 继续访问电脑版

热点推荐

查看: 22|回复: 0

JavaScript中的神秘函数闭包-蛙课网

[复制链接]
  • TA的每日心情
    奋斗
    3 小时前
  • 签到天数: 36 天

    [LV.5]常住居民I

    64

    主题

    95

    帖子

    961

    积分

    高级会员

    Rank: 4

    积分
    961
    发表于 2020-9-11 16:50:23 | 显示全部楼层 |阅读模式

    闭包就是能够读取其他函数内部变量的函数。例如在JavaScript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。让我们一起来了解JavaScript中的神秘函数闭包

    闭包包含自由(未绑定到特定对象)变量,这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。“闭包” 一词来源于以下两者的结合:要执行的代码块(由于自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境(作用域)。在PHP、Scala、Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby、 Python、Go、Lua、objective c、swift 以及Java(Java8及以上)等语言中都能找到对闭包不同程度的支持。

    局部变量无法共享和长久的保存,而全局变量可能造成变量污染,所以我们希望有一种机制既可以长久的保存变量又不会造成全局污染。于是,闭包函数诞生了。闭包在JavaScript高级程序设计(第3版)中是这样描述:闭包是指有权访问另一个函数作用域中的变量的函数。那么闭包的作用也就很明显了。

    1. 可以在函数的外部访问到函数内部的局部变量。

    2. 让这些变量始终保存在内存中,不会随着函数的结束而自动销毁。

    从本质上来看,集合 S 是闭集当且仅当 Cl(S)=S(这里的cl即closure,闭包)。特别的,空集的闭包是空集,X 的闭包是 X。集合的交集的闭包总是集合的闭包的交集的子集(不一定是真子集)。有限多个集合的并集的闭包和这些集合的闭包的并集相等;零个集合的并集为空集,所以这个命题包含了前面的空集的闭包的特殊情况。无限多个集合的并集的闭包不一定等于这些集合的闭包的并集,但前者一定是后者的父集。

    若 A 为包含 S 的 X 的子空间,则 S 在 A 中计算得到的闭包等于 A 和 S 在 X 中计算得到的闭包(Cl_A(S) = A ∩ Cl_X(S))的交集。特别的,S在 A 中是稠密的,当且仅当 A 是 Cl_X(S) 的子集。接下来我们看一段实例:

    JS代码:

    function f1(){

    var n=999;

    nAdd=function(){n+=1}

    function f2(){

    alert(n);

    }

    return f2;

    }

    var result=f1();

    result(); // 999

    nAdd();

    result(); // 1000

    在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。


    为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

    这段代码中另一个值得注意的地方,就是“nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此 nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个

    匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

    1.定义外层函数,封装被保护的局部变量。

    2.定义内层函数,执行对外部函数变量的操作。

    3.外层函数返回内层函数的对象,并且外层函数被调用,结果保存在一个全局的变量中。

    由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

    闭包会在父函数外部,改变父函数内部变量的值。所以,如果把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

    简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。这是对闭包作用的非常直白的描述,不专业也不严谨,但大概意思就是这样,理解闭包需要循序渐进的过程。

    理解JavaScript的神秘函数闭包是成为一名高级JS程序员的先决条件,理解了其解释和运行机制才能写出更为安全和优雅的代码。掌握了JavaScript中的这一神秘函数,我们才能在学习JS的道路上风雨兼程,一路前行!





    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    快速回复 返回顶部 返回列表