简单介绍一下闭包及它的一些应用场景

简介: 闭包是什么? ——可简单理解为:**有权访问另一个函数作用域内变量的函数都是闭包。**

前言

我是在大一下,一个学姐面试的时候,第一次听闻闭包这个名词。当时听了一些学长的解释(虽然没怎么听懂),但是觉得,似乎很高级的样子。

如今时隔一年,跟闭包也打了不少交道,终于也能谈一谈自己对于它的理解了。

什么是闭包?

闭包是什么? ——可简单理解为:有权访问另一个函数作用域内变量的函数都是闭包。

先来看一个例子:

function drink() {
    var beerName = "雪花啤酒";
    let beerNum1 = 1;
    const beerNum2 = 2;
    var innerBeer = {
        getBeer:function() {
            console.log(beerNum1)
            return beerName
        },
        setBeer:function(newBeer) {
            beerName = newBeer
        }
    }
    return innerBeer
}
var go = drink();
go.setbeer("闷倒驴");
go.getBeer();
console.log(go.getBeer())

当我们使用到getBeer与setBeer这两个函数的时候,它们内部是没有变量beerNum1与beerName的,那么它们这个时候会怎么办呢,学过作用域链的小伙伴可能会了解,它们这个时候就会到外层去找,也就是去drink函数中去找,找到了,于是乎可以使用了。

但是呢,问题又来了,drink是个函数,它的作用域叫做函数作用域,在drink函数执行完,这个作用域是要被销毁的,那么这个时候,innerBeer又该怎么做呢?

还是因为作用域链的原因,即使drink已经执行完了,当innerBeer再次调用其下的两个方法时,它用到的变量,是不能被销毁的,也就是说,beerNum1与beerName被迫成为了钉子户

innerBeer:我只要在用,你就不能销毁!

而这,就是闭包。

闭包:这就是我

为什么说闭包容易产生内存泄漏?

首先我们要知道一个概念:什么是内存泄漏?

当内存中产生了不能被回收的变量,就叫内存泄漏

还是看刚刚的那个例子,var go = drink();

go是一个全局变量,无论在什么时候都可以调用setBeer与getBeer,因为我们将函数的返回值赋值给了它,只要页面没有销毁,它就会一直存在。而setBeer跟getBeer又会用到beerNum1与beerName,也就是前文中我们提到的,钉子户理论。结合JavaScript的垃圾回收机制,我们现在知道,它们两个钉子户是不可能被清除掉的了。

这块存有beerNum1与beerName的内存,只有setBeer与getBeer才能访问到,别人是访问不到的。而它也不属于哪一个执行上下文中,所以它也销毁不掉。

所以就说,闭包容易产生内存泄漏的问题

只要页面不关闭,这个变量就一直在,导致存在内存泄漏的问题

为什么还要使用闭包?

张三(👀没错就是法外狂徒本三)就说了:闭包既然会产生内存泄漏的问题,那我们为什么还要去使用它呢?

还不是因为,我们在某些情况下,希望某些函数内的变量在函数执行后不被销毁(我也知道,好像有那么一丝剑意)。

张三又有疑问了:那为什么干脆不定义成全局变量呢?现在搞得你还回收不了。

如果创建全局变量的话,它很容易就会被污染,同名变量,或者被一些函数修改等。为了避免它被篡改,又想让它长时间保存,让他变得形似一个全局变量,可以随时去用,我们就会在这个时候,使用闭包!

请注意:闭包一定要慎用

闭包的应用

查了几个闭包的应用,学习一下ing

  • 模仿块级作用域

    • 计时器的一个应用
    for (var i = 0; 1 < 10; i++) {
          (function (j) {
            setTimeout(function () {
              console.log(j);
            }, 1000 * j)
          })(i)
        }
    • 打印一组li的下标
    for(var i = 0; i < lis.length; i++) {
        (function(j) {
            lis[j].onclick = function() {
                alert(j)
            }
        })(i)
    }
  • 埋点计数器

    • 产品让做的网站分析的一种常用的数据采集方法
    function count() {
        var num = 0;
        return function() {
            return ++num
        }
    }
    var getNum = count();  // 第一个需要统计的地方
    var getNewNum = count(); //第二个需要统计的地方
     // 如果我们统计的是两个button的点击次数
    document.querySelectorAll('button')[0].onclick = function() {
         console.log('点击按钮1的次数:'+getNum());
    }
    document.querySelectorAll('button')[0].onclick = function() {
         console.log('点击按钮2的次数:'+getNewNum());
    }
  • 柯里化

    • 把一个多参数的函数转化成单参数函数的方法,使得更灵活方便
    // 原函数 用来检验文本是否符合规范
    // reg 传入的正则表达式  txt 需要被检测的文本
    function check(reg,txt){
        return reg.test(txt)
    }
    console.log(check(电话号码的正则,13923456789));
    console.log(check(邮箱的正则,youxiang@163.com));
    
    // 现如今
    function nowCheck(reg){
        return function(txt){
            return reg.test(txt)
        }
    }
    var isPhone = nowCheck(电话号码的正则)
    console.log(isPhone('13923456789'))
    var isEmail = nowCheck(邮箱的正则)
    console.log(isEmail('youxiang@163.com'))

总结:简单说一下闭包吧

闭包产生的原因

函数中的局部变量在函数执行完后会被销毁,有时候,我们不希望这个局部变量会被销毁,我们还想在外部进行持续的操作和访问,我们就会用到闭包这种方式。

为什么不创建一个全局变量来代替这个局部变量?

因为全局变量会被污染或者被修改。

闭包能够访问里面的变量,是由于作用域链,用到了函数嵌套中,内部函数能够访问父级函数作用域的变量这个理念。

闭包能够造成内存泄漏

页面不关闭,变量就一直在,不能被垃圾回收机制回收或者手动清除。

相关文章
|
自然语言处理 JavaScript 前端开发
谁才是真正的协议之王?fastjson2 vs fury
谁才是真正的协议之王?fastjson2 vs fury
558 1
串口网口16进制发送的和ASCII发送以及16进制接收和ASCII接收区别
我们在工控软件中,会经常使用到网口和串口,去接受和发送数据。通常我们发送数据的模式有两种,一种16进制,一种是ASCII码。16进制的的经常会用来和仪器PLC等设备通讯。ACSII码是一种文本模式。
1685 0
串口网口16进制发送的和ASCII发送以及16进制接收和ASCII接收区别
|
缓存 Linux 开发工具
CentOS 7- 配置阿里镜像源
阿里镜像官方地址http://mirrors.aliyun.com/ 1、点击官方提供的相应系统的帮助 :2、查看不同版本的系统操作: 下载源1、安装wget yum install -y wget2、下载CentOS 7的repo文件wget -O /etc/yum.
253941 0
|
Linux 数据安全/隐私保护 Windows
更换(Pypi)pip源到国内镜像
pip国内的一些镜像 阿里云 http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.
247088 2
|
11月前
|
机器学习/深度学习 人工智能 自然语言处理
软件测试中的人工智能革命:提升测试效率与质量的新篇章
随着人工智能技术的不断成熟,其在软件测试领域的应用正逐渐改变传统测试方式。本文将探讨AI在软件测试中的应用现状、优势以及面临的挑战,并通过具体案例分析展示AI如何提高测试效率和质量。最后,我们将讨论未来AI在软件测试中的发展趋势及其对人类测试工程师角色的影响。
978 4
|
12月前
|
人工智能 算法 测试技术
软件测试中的人工智能:提升测试效率与质量
随着软件开发的快速发展,传统的手工测试方法已经无法满足现代软件项目的需求。本文探讨了人工智能在软件测试中的应用,如何通过自动化测试、智能缺陷分析和测试用例生成等技术,提高测试效率和质量。我们将详细介绍这些技术的原理和实际应用,并讨论其带来的优势和挑战。
621 4
|
JavaScript
如何在 vue3 中使用 jsx/tsx?(上)
如何在 vue3 中使用 jsx/tsx?(上)
660 0
|
Java
JAVA读取EMF文件并转化为PNG,JPG,GIF格式
JAVA读取EMF文件并转化为PNG,JPG,GIF格式
622 0
|
JavaScript 前端开发
「Vue3系列」Vue3 事件处理
在 Vue 3 中,事件处理与 Vue 2 非常相似,但有一些细微的改进和新的语法。Vue 3 仍然使用 `v-on` 指令来处理 DOM 事件,或者更常见的是使用其简写形式 `@`。
896 0
|
存储 缓存 负载均衡
HBase 详细API操作
HBase 详细API操作
287 0