Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >javaScript核心技术--“闭包”,不看绝对后悔!

javaScript核心技术--“闭包”,不看绝对后悔!

作者头像
Java深度编程
发布于 2020-06-10 06:51:03
发布于 2020-06-10 06:51:03
42200
代码可运行
举报
文章被收录于专栏:Java深度编程Java深度编程
运行总次数:0
代码可运行

“闭包”,又称“定义在函数内部的函数”,闭包技术是javaScript中很关键的核心技术,很多框架的研发或者企业高端技术都需要使用到它。要理解闭包技术,必须先弄明白“变量的作用域”。 1.变量的作用域 javaScript沿袭的java的变量规则,但稍有改进。和java一样可分为“全局变量”和“局部变量”,在javaScript中的“局部变量”又称之为函数变量。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制


    var x = 999;
 
    function f1() {
      var y = 888;
      console.log(x); 
      console.log(y); 
    }
    f1() // 999  888
    console.log(y); // Uncaught ReferenceError: n is not defined

由上可知javaScript和java一样,父对象的所有变量,对子对象都是可见的,反之则不成立。而有些时候需要在外部父对象中获取子对象区域内部的变量,正常情况下是无法做到的,这时候就需要用到“闭包”技术了。

2.什么是闭包 请先看以下的函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制


    function f1() {
      var n = 999;
      function f2() {
      console.log(n); // 999
      }
    }

上面代码中,函数f2就在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。这就是 JavaScript 语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。上面的代码中内部函数分f2()就是“闭包”,一个定义在函数内部的函数。 3.闭包的用途 3.1. 突破局域限制,读取函数内部的变量值。 逻辑思维分析: 上面我们已经知道了函数f2()就是闭包,那么我们如果去使用它获取函数内部的变量呢? 分析:既然f2可以读取f1的局部变量,那么只要把f2作为返回值,我们不就可以在外部得到返回值,进而间接读取它的内部变量了吗!

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制


    function f1() {
      var n = 999;
      function f2() {
        console.log(n);
      }
      return f2;
    }
 
    var result = f1();
    result(); // 999

上面代码中,函数f1的返回值就是函数f2,由于f2可以读取f1的内部变量,所以就可以在外部获得f1的内部变量了。

3.2.“记住”诞生的环境 闭包最大的特点,就是它可以“记住”诞生的环境,比如f2记住了它诞生的环境f1,所以从f2可以得到f1的内部变量。在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。它可以让这些变量始终保持在内存中,使得它诞生环境一直存在。 现在,假设我们有一个需求:每调用一次函数,都记录这个函数的被调用的次数。如何实现?用我们常规的思维,肯定是定义一个外部变量,然后每调用一次就++,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制


    var start = 0;
    function test_01() {
      start++;
    }
 
    test_01();
    start // 1
    test_01();
    start // 2
    test_01();
    start // 3

你们会发现,上面的方式完美的实现了。但假如需求在改动一下,函数test_01()内部还有一个函数test_02(),要录test_02()函数被调用的次数,这个时候如何实现呢?我们继续按上面的套路搬砖:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制


    var start = 0;
    function test_01() {
 
        function test_02() {
            start++;
        }
    }
 
    test_01();
    start // 0
    test_01();
    start // 0
    test_01();
    start // 0

这时候你们会发现,无论你调用多少次函数,start都不会增长,一直是0。why? 但如果你把上面的代码改一改,将函数test_02作为返回值,并且外部定义一个变量接受它,就不一样了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制


    var start = 0;
    function test_01() {
 
       return function test_02() {
            start++;
        }
    }
 
    var temp = test_01();
    temp ();
    start // 1
    temp ();
    start // 2
    temp ();
    start // 3

可以看到start的值又神奇般的增长了。这究竟是为什么呢?你是否感觉到了想破脑袋也想不明白是为什么?哈哈…… 其实这就是闭包技术的一种体现。用比较科学的术语来技术就是:“temp始终在内存中,而temp的存在依赖于函数test_01(),函数test_01()也因此始终在内存中,不会在调用结束后,被垃圾回收机制回收。所以它才能一直记录下这个‘诞生环境’ ”。 上面的这种解释可能过于“科学语言”,让人难以理解。因此我用比较通俗的语言来解释:因为我在外部声明了一个变量temp,它调用了函数test_01(),而test_01()又返回了函数test_02()。所以上面的代码可以等价与下面的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制


    var start = 0;
    function test_01() {
 
       return function test_02() {
            start++;
        }
    }
 
    var temp = function test_02() {
            start++;
        };
    temp ();
    start // 1
    temp ();
    start // 2
    temp ();
    start // 3

上面我举的第一个例子就已经很好的说明了,在同一个作用域操作一个变量是可以成功的。这种变换操作手法更this的作用域极其相似。javaScript中this始终指向当前对象,然而this的指向却是动态的。说到这里了我就随便提一提this的作用域吧。 this的作用域

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制


 
    var A = {
      name: '张三',
      describe: function () {
        return '姓名:'+ this.name;
      }
    };
 
    var B = {
      name: '李四'
    };
 
    B.describe = A.describe;
    B.describe()
    // "姓名:李四"
 
    var name = '龚文学';
    var tenp = function () {
        return '姓名:'+ this.name;
      };
 
    temp(); // 姓名:龚文学

从上面可以看出在A对象和B对象调用同一个函数this的指向不同,所以输出了不能的结果。如果把这个函数提取出来,赋值给一个变量,this的指向就是最顶层的window对象,这个时候就输出了我的顶顶大名--“龚文学”。这与“闭包”的方式十分类似,我以此举例说明,希望能帮助大家理解。如果大家还是有不懂的地方,请在微信公众平台《Java深度编程》留言。

3.3.封装对象的私有属性和私有方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制


    function Person(name) {
      var _age;
      function setAge(n) {
        _age = n;
      }
      function getAge() {
        return _age;
      }
 
      return {
        name: name,
        getAge: getAge,
        setAge: setAge
      };
    }
 
    var p1 = Person('张三');
    p1.setAge(25);
    p1.getAge() // 25

上面代码中,函数Person的内部变量_age,通过闭包getAge和setAge,变成了返回对象p1的私有变量。因为闭包能一直记住之前的环境,所以Person的内部变量会随之永久改变,这与java的get,set方式十分类似。 4.闭包的弊端 注意,因为外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,外层函数多次运行后会导致内存消耗很大。因此不能滥用闭包,否则会造成网页的性能问题。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-10-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java深度编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
RHEL正式限制访问它的源代码,这意味着什么?
近日,Redhat公司对RHEL的源代码访问做了变更. 这是对Linux服务器生态有比较大影响的一个事件.
御剑
2023/08/31
7760
RHEL正式限制访问它的源代码,这意味着什么?
Centos 系统后期不维护,用什么系统进行替代比较好?
Linux运维技术之路
2025/01/17
1.6K0
Centos 系统后期不维护,用什么系统进行替代比较好?
CentOS 8/6宣布停用,来试试这些最佳替代方案吧!
点击上方“芋道源码”,选择“设为星标” 管她前浪,还是后浪? 能浪的浪,才是好浪! 每天 10:33 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | Java 2021 超神之路,很肝~ 中文详细注释的开源项目 RPC 框架 Dubbo 源码解析 网络应用框架 Netty 源码解析 消息中间件 RocketMQ 源码解析 数据库中间件 Sharding-JDBC 和 MyCAT 源码解析 作业调度中间件 Elastic-Job 源码解析 分布式事务中间件 TCC-Transaction
芋道源码
2022/03/24
1.4K0
CentOS 8/6 Linux 生命终结,2022 年最好的替代方案是什么?
◆ 前言 Red Hat 最近宣布,CentOS 8 Linux将不再支持并在 2021 年底停止使用。取而代之的是滚动版本 CentOS Stream 作为 RHEL 的下游分支于 2019 年推出,将持续排查漏洞,让上游版本更加稳定和安全。 但是,运行 CentOS 7 的服务器不会受到影响。他们将与 RHEL 7 生命周期并行更新。RHEL 7 将在 2024 年结束其最后一个维护周期。 但是,如果您使用的是 CentOS 8,那么 2022 年有哪些替代方案?不幸的是,即使您找到了,服务器应用程序的
IT大咖说
2022/03/08
6.6K0
CentOS替代榜单,哪个才是最佳选择
如今CentOS更新维护停止后,很多用户和企业需要更换新的操作系统做替代。阿祥今天介绍几款操作系统,对比他们的优势、劣势。涉及成本、社区支持性、兼容性等方面。榜单如下,这榜单是否有异议?
ICT系统集成阿祥
2024/12/03
3.8K0
CentOS替代榜单,哪个才是最佳选择
四款最佳替代 CentOS 的操作系统
在互联网企业,对于服务器操作系统的选择上,不难发现,大家都更多倾向于 CentOS 系统。
民工哥
2024/09/13
2.5K0
四款最佳替代 CentOS 的操作系统
ubuntu与centos的对比和选择「建议收藏」
CentOS(Community ENTerprise Operating System)是Linux发行版之一,它是来自于Red Hat Enterprise Linux依照开放源代码规定释出的源代码所编译而成。RedHat Enterprise Linux (RHEL)是企业发行版。它每五年左右更新一次,在系统的稳定性,前瞻性和安全性上有着极大的优势。由于CentOS出自同样的源代码,因此要求高度稳定性的服务器以CentOS替代商业版的Red Hat Enterprise Linux使用。CentOS通常在RedHat的发布后就会很快发行。我们使用CentOS的原因在于RHEL发行版的标准支持服务费用非常高,大约每台服务器800美元左右,对于我们很多拥有数十台甚至上百台服务器的用户来说,这是必须要控制的成本。 Ubuntu是一个以桌面应用为主的Linux操作系统。Ubuntu基于Debian发行版和GNOME桌面环境,与Debian的不同在于它每6个月会发布一个新版本。Ubuntu的目标在于为一般用户提供一个最新的、同时又相当稳定的主要由自由软件构建而成的操作系统。Ubuntu具有庞大的社区力量,用户可以方便地从社区获得帮助。
全栈程序员站长
2022/10/03
15.2K0
ubuntu与centos的对比和选择「建议收藏」
从CentOS 8到CentOS Stream,到底发生什么事了?
在Linux服务器操作系统领域,CentOS一直被认为是一个稳定安全并且可靠的发行版本。它是从RHEL源代码复刻,去除了RHEL有关的商标等一些内容构建出来的。
御剑
2021/09/29
22.2K0
开源不等于免费:Red Hat 调整 CentOS 项目带来的思考
最近关于 Red Hat,CentOS 以及开源等方面有很多讨论,每个人都有各自的观点和看法,其实在 CentOS Linux 宣布后续停止发布,推出 CentOS stream时我就想写相关内容来着,后来只是和同事们进行了一些内部交流并未成文。
Jintao Zhang
2023/09/03
1.3K0
开源不等于免费:Red Hat 调整 CentOS 项目带来的思考
CentOS 将于年底终止!
一年前Red Hat宣布将在今年底(2021年)结束提供免费的CentOS Linux(CentOS 已死!"免费"的 RHEL 没了...)。上周五Red Hat再度提醒,CentOS Linux 8将在今年12月31日来到它的生命周期终点(End of Life,EoL)。对于:CentOS 停止服务!我们用哪个?Ubuntu or Debian?
民工哥
2021/12/21
1.9K0
CentOS 将于年底终止!
CentOS 8退役倒计时,开发者们又吵起来了
作者 | 核子可乐、褚杏娟 怎么迁?这是个问题。 CentOS 8 将在 2021 年底走完自己的生命周期,这远远早于最初定下的 2029 年。虽然该消息早在去年 12 月就已经公布,但不少开发者仍对此感到无所适从。运行 CentOS 8 的系统不会一夜之间崩溃,只是从明年年初开始一切安全及其他更新都将不再继续。CentOS 项目表示用户应把 CentOS Stream 作为替代方案,但用户们仍有很多自己的顾虑。 突如其来的终结 CentOS 起源于 CAOS Linux 的构建,是一种基于 RPM 的
深度学习与Python
2023/04/01
7380
CentOS 8退役倒计时,开发者们又吵起来了
openSUSE Leap和openSUSE Tumbleweed有什么区别,选哪个?alma linux和rocky linux选哪个?
openSUSE Leap 和 openSUSE Tumbleweed 是 openSUSE 项目的两个主要发行版。它们的主要区别在于发布模式、更新速度和稳定性。以下是它们之间的一些区别:
Windows技术交流
2024/07/02
1.1K0
取代CentOS!AlmaLinux测试版已发布
上个月红帽突然宣布不再维护 CentOS Linux 后,CentOS Linux 的创建者 Gregory M. Kurtzer 随即宣布将创建一个新项目 Rocky Linux 替代 CentOS Linux,CloudLinux 公司也宣布启动了类似的 Lenix 项目。 昨天,CloudLinux 正式宣布了 Lenix 的测试版。不过,在宣布该项目的最新进展时,CloudLinux 还将 Lenix 更名为了 AlmaLinux。
IT大咖说
2021/02/24
1.6K0
取代CentOS!AlmaLinux测试版已发布
红帽对 RHEL 下游造成毁灭性打击!停止公开企业版源代码,要挤占开源份额实现盈利?
当地时间 6 月 21 日,红帽发布公告称,停止向第三方提供 RHEL 源代码,CentOS Stream 将成为公共 RHEL 相关源代码发布的唯一仓库。红帽的客户和合作伙伴可以付费获得源代码,但无权二次发布这些代码。
深度学习与Python
2023/08/09
4730
红帽对 RHEL 下游造成毁灭性打击!停止公开企业版源代码,要挤占开源份额实现盈利?
年中了,留给CentOS8的日子不多了!
2020年12 月 8 日,CentOS 开发团队在其官博宣布,CentOS 8 将在 2021 年底结束支持,也就意味着不会有 CentOS Linux 9,CentOS 10的出现了。
xjjdog
2021/05/27
8320
OpenELA公开发布Red Hat Enterprise Linux源代码
OpenELA 已将其进程自动化,以便在 RHEL 新版本发布后几天内即可获得新的企业 Linux 源。
云云众生s
2024/07/22
3150
Red Hat 杀死了CentOS后 Rocky Linux 面世
作者:Abhishek Prakash是专业软件开发人员,也是It's FOSS网站的创始人。他是一名Linux拥趸和开源爱好者。
公众号: 云原生生态圈
2020/12/14
2.4K0
Red Hat 杀死了CentOS后 Rocky Linux 面世
2021 年7 个值得期待的 Linux 发行版
elementary OS 6 基于Ubuntu 20.04 LTS,专注于改善用户体验,有暗模式体验,是最漂亮的 Linux 发行版之一,下一次升级可能是一个巨大的改进。
网络技术联盟站
2021/10/29
9200
2021 年7 个值得期待的 Linux 发行版
后 CentOS 时代,作为服务器使用我们该选什么 Linux?
根据官网最新的产品规范,CentOS 7 在 2024 年停止支持,CentOS 8 将在今年年末停止支持。
章鱼猫先生
2021/10/15
2.5K0
后 CentOS 时代,作为服务器使用我们该选什么 Linux?
Linux 下 12 个最佳 Notepad++ 替代品
Notepadd++ 是一款完全免费的源代码编辑器,旨在替代 Windows 上的记事本 – 基于 Scintilla 用 C++ 编写,并实现 Win32 API 和 STL,以确保程序尺寸小且执行速度快 – 这些特性使其成为一个家族开发者中的名字。遗憾的是,没有适用于 Linux 用户的版本。
数据科学工厂
2023/11/01
2.8K0
Linux 下 12 个最佳 Notepad++ 替代品
推荐阅读
相关推荐
RHEL正式限制访问它的源代码,这意味着什么?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验