一文详解js闭包,初学者也能学会的闭包

2023-05-16

目录

一、前提知识:变量的作用域

二、闭包的理解

三、闭包的作用

四、常见的闭包使用形式

五、闭包的生命周期

六、注意事项 


一、前提知识:变量的作用域

变量的作用域分为全局作用域和局部作用域,也就是全局变量和局部变量。JavaScript有一个特殊的地方是函数内部可以直接读取全局变量,但是在函数外部,无法读取到函数内部的变量。

  • 函数内部直接读取全局变量:
//函数内部直接读取全局变量
var a = 100
function fn1(){
   console.log(a)
}
fn1() //100
  • 函数外部无法读取函数内的局部变量
//函数外部无法读取函数内的局部变量
function fn1(){
    var a = 100
}
console.log(a) //error

这里注意:在函数内部声明变量的时候,一定要使用var命令。如果不用的话,实际上声明了一个全局变量!

function fn1(){
    a = 100
}
console.log(a) //100

那么问题来了:

对函数内部变量进行一系列操作之后,需要在函数外部访问到,怎么才能实现呢?这就需要使用闭包了。

二、闭包的理解

针对上述问题:我们可以在函数内部嵌套一个子函数,将子函数作为外部函数的返回值。如下:

<script>
    function fn1(){
      var myName = "唯一的阿金"
      function fn2(){
        console.log("myName = ",myName)
      }
      return fn2
    } 
    var result = fn1()
    result() 
</script>

打印结果如下:

 

在上面的代码中,函数 fn2 被包括在函数 fn1 内部,这时 fn1 内部的所有局部变量,对 fn2 都是可见的。但是,fn2 内部的局部变量,对 fn1是不可见的。这是 Javascript 特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

我们可以利用这一特点,把 fn2 作为返回值,就可以在fn1函数外部访问 fn1 的内部变量了。这个fn2函数,就是闭包。

简单理解,闭包就是能读取函数内部变量的函数。

闭包的产生条件:

当一个嵌套的内部函数引用了嵌套的外部函数的变量(这个变量也可以是函数)时,闭包就产生了。

三、闭包的作用

 闭包有两大作用:

  1. 在函数外部读取函数内部的变量
  2. 让这些变量的值始终保持在内存中,不被销毁
<script>
    function fn1(){
      var myName = "唯一的阿金"
      addName = function(){
        myName += ",你好!"
      }
      function fn2(){
        console.log("myName = ",myName)
      }
      return fn2
    } 
    var result = fn1()
    result()
    addName()
    console.log("*****调用addName()后****")
    result()
</script>

打印结果如下:可以看到函数内部的局部变量myName在函数调用后并没有被销毁,在执行addName函数(它是一个全局变量)后,改变了myName变量的值。

四、常见的闭包使用形式

1. 将函数作为另一个函数的返回值使用

这种形式,上述代码已经演示过,这里不再赘述。

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

function showDelay(msg,time){
    setTimeout(function(){
        console.log(msg)
      },time)
    }
showDelay("唯一的阿金,你好!",1000)

setTimeout()函数的第一个参数是函数,同时函数内部调用了外部函数showDelay()的局部变量,因此产生了闭包。

 

闭包的应用主要有:

  • 模仿块级作用域,
  • 实现柯里化,
  • 在构造函数中定义特权方法、
  • Vue中数据响应式Observer中使用闭包等。

五、闭包的生命周期

 1. 产生:在内部函数定义执行时产生

<script>
    function fn1(){
      var myName = "唯一的阿金"
      function fn2(){
        console.log("myName = ",myName)
      }
      return fn2
    } 
    var result = fn1()  //产生闭包
    result() 
</script>

 2. 死亡:在内部函数成为垃圾对象时 

<script>
    function fn1(){
      var myName = "唯一的阿金"
      function fn2(){
        console.log("myName = ",myName)
      }
      return fn2
    } 
    var result = fn1()  //产生闭包
    result = null //闭包死亡
</script>

六、注意事项 

1. 闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。

  • 解决方法:在退出函数之前,将不使用的局部变量全部删除。

2. 由于闭包会在父函数外部,改变父函数内部变量的值。因此,在把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value)时,要小心,不要随便改变父函数内部变量的值。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一文详解js闭包,初学者也能学会的闭包 的相关文章

  • [ROS]Ubuntu18.04下安装指定版本OpenCV

    Linux xff1a Ubuntu 18 04 ROS xff1a ROS Melodic 目录 1 获取 OpenCV 源代码2 安装所需的依赖软件包3 使用CMake从源代码编译OpenCV3 1 准备3 2 配置OpenCV3 3
  • [ROS](12)ROS通信 —— 参数服务器(Parameter Server)通信

    文章只是个人学习过程中学习笔记 xff0c 主要参考ROS教程1 2 ROS xff08 01 xff09 创建ROS工作空间 ROS xff08 02 xff09 创建 amp 编译ROS软件包Package ROS xff08 03 x
  • zabbix4.0学习六:Zabbix监控日志

    zabbix4 0学习六 xff1a Zabbix监控日志 前言 我们希望监控日志 xff0c 在日志出现特定标识或字符串时打印出日志 xff0c 并邮件通知我们 xff0c 以便我们手动处理 xff08 当然使用动作可自动处理 xff09
  • 听说你会Promise? 那么如何控制请求并发数呢?

    前言 现在面试过程当中 xff0c 手写题必然是少不了的 xff0c 其中碰到比较多的无非就是当属 请求并发控制了 现在基本上前端项目都是通过axios来实现异步请求的封装 xff0c 因此这其实是考你对Promise以及异步编程的理解了
  • [ROS]在VS Code下编写代码,汇总问题及解决办法

    Linux xff1a Ubuntu18 04 ROS xff1a melodic 在VS Code下编写代码 xff0c 汇总问题及解决办法 问题1 xff1a 编译C 43 43 代码可通过 xff0c 但抛出错误警告以及代码补全异常
  • 基本类型与包装(装箱)类型的区别

    Java的类型分为两部分 xff0c 一个是基本类型 xff08 primitive xff09 xff0c 如int double等八种基本数据类型 xff1b 另一个是引用类型 xff08 reference type xff09 xf
  • 学习笔记------关于字符串结束符'\0'、字符串定义方法

    字符串定义方法 有2种方法 xff1a 1 xff09 字符数组 2 xff09 字符指针 初始化 1 xff09 字符数组方式初始化大致3种 xff1a 1 char str 10 61 34 12345 34 或者char str 10
  • 树莓派连接vnc教程

    1 输入 sudo raspi config 进入到系统设置中开启vnc服务 2 进入后选择 Interfacing Options 进入 3 选择 VNC 进入 4 yes 下载软件 xff1a VNC Viewer 5 连接vnc xf
  • ubuntu 22.04设置root密码,与开启sshd服务

    1 sudo passwd root 直接输入两次密码即可完成 2 安装sshd服务 xff1a apt install ssh 3 启动ssh服务 systemctl start sshd 4 设置开机启动 xff1a systemctl
  • Python+Flask+Docker+Vue实现简单的股票数据统计

    闲暇时间实现了一个简单的股票数据统计功能 数据是从网上爬下来的 xff0c 页面支持按照股票名称 股票代码 股票类型 股价 市值等搜索并展示在下方列表 除了股票的基本信息以外 xff0c 还会显示其他炒股软件上不会展示的信息如流动比率 速动
  • [2020-07-23]备战考博的一点点经历

    首先声明 xff0c 博主只是个普通人 xff0c 不是北清复交那种天才选手 xff0c 本硕都是普通一本 xff0c 像个不断前进的蜗牛一样 xff0c 好不容易还有继续往上爬的机会 xff0c 所以博主只会从一个普通学生的视角去讲自己的
  • 遇见Java

    Java是一门面向对象的编程语言 xff0c 不仅吸收了C 43 43 语言的各种优点 xff0c 还摒弃了C 43 43 里难以理解的多继承 指针等概念 xff0c 因此Java语言具有功能强大和简单易用两个特征 Java语言作为静态面向
  • STM32F103移植FreeRTOS警告记录

    1 xff1a 新建MDK工程 xff0c 选择文件存放路径 xff0c 选择芯片型号 xff0c 创建一个USER文件 xff0c 复制自动创建的文件到USER文件中 xff0c 关闭程序 创建一个OBJ目标文件夹 xff0c 打开软件选
  • tensorflow实现简单的卷积神经网络

    1 卷积神经网络 xff08 Convolutional Neural Network xff0c CNN xff09 优点 xff1a xff08 1 xff09 直接使用图像的原始像素作为输入 xff0c 不必先使用SIFT等算法提取特
  • zabbix4.0学习八:JMX有能监控哪些监控项详说

    zabbix4 0学习八 xff1a JMX有能监控哪些监控项详说 文章目录 zabbix4 0学习八 xff1a JMX有能监控哪些监控项详说 前言远程连接tomcat远程连接java 前言 在使用jmx监控tomcat时一直好奇MBea
  • 排序算法之冒泡排序、选择排序、插入排序的区别与联系

    冒泡排序 xff08 1 xff09 算法 xff1a 假如有N项数据 第一趟 xff0c 将首项与第二项比较 xff0c 较小者放在前面 xff0c 较大者放后面 xff0c 然后比较第二项和第三项 xff0c 依次进行 xff0c 第一
  • 排序算法之快速排序算法

    核心思想 xff1a xff08 1 xff09 要排序的一组数据中取一个数为 基准数 xff08 2 xff09 通过一趟排序将要排序的数据分割成独立的两部分 xff0c 其中左边的数据都比 基准数 小 xff0c 右边的数据都比 基准数
  • 数据结构之树知识汇总——思维导图

  • Linux基础学习与VMWare的安装和使用

    一 Linux入门概述 1 1 概述 Linux内核最初只是由芬兰人林纳斯 托瓦兹 xff08 Linus Torvalds xff09 在赫尔辛基大学上学时出于个人爱好而编写的 Linux是一套免费使用和自由传播的类Unix操作系统 xf
  • OJ刷题之1035:列车长的烦恼

    OJ刷题之1035 xff1a 列车长的烦恼 1 题目以及要求2 题目解析3 代码思路 1 题目以及要求 description John是个小列车站的站长 xff0c 每次列车在这里重新编组时他就很烦恼 因为站上只有一个人字形的编组轨道

随机推荐