当前位置: 首页 > news >正文

闭包:什么是闭包、闭包的作用、闭包的解决

这是我最烦的东西,没有之一!一万头草泥马狂奔而过!

说明

  • 在JS中,函数可以赋值给一个变量,而JS又是弱类型语言,所以在JS中函数就可以作为参数或者是返回值。
  • 什么是闭包?函数嵌套函数,并且内层函数作为返回值,引用外部函数的参数或变量。
  • 闭包在vue项目中的使用?

 学习闭包我们要清楚函数作用域、内存回收机制、作用域继承。

1、什么是闭包 

1.1 函数作用域

作用域我们可以认为它是一个封闭的盒子,只让它在这个盒子里面进行操作,也可以称这个盒子为独立作用域。在js中,一个函数要执行时就会在内存里面创建一个独立作用域————封闭的盒子。

比如在函数中第一一个变量,只能在函数这个独立作用域中使用(也就是封闭的盒子)。只要跳出这个作用域,就找不到该变量了。

而且函数执行完毕之后,这个独立作用域或(封闭的盒子)就会删除。有一种情况下这个封闭的盒子是不会删除的,那就是“闭包”,后面会讲到。

1.2 内存回收机制

内存回收机制就是不在用到的内存空间,系统会自动进行清理出空间提供给其他程序使用。那回收的前提是什么呢?

内部函数引用外部的函数的变量,外部函数执行完毕,作用域也不会删除。从而形成了一种不删除的独立作用域。

某一个变量或者对象被引用,因此在回收的时候不会释放它,因为被引用代表着被使用,回收机制不会对正在引用的变量或对象进行回收的。

1.3 作用继承

所谓的作用域继承,就像是儿子可以继承父亲的财产一样。比如我这里有一个大的盒子作为一个父级的作用域,然后在这个大的盒子里边放一个小的盒子,作为子作用域。我们规定可以在小盒子中获取到大盒子中的东西,大盒子不能获取小盒子里的东西就称为作用域继承。

在 JS 中,道理是一样的,在一个函数里边我们再声明一个函数,内部函数可以访问外部函数作用域的变量,而外部的函数不能获取到内部函数的作用域变量。

那好,上边的这几个概念理解了之后,什么是闭包对你来说已经不是什么问题。

什么是闭包,那就是在一个函数里边再定义一个函数。这个内部函数一直保持有对外部函数中作用域的访问(小盒子可以一直访问大盒子但大盒子不能访问小盒子)。

函数执行,形成一个独立作用域,保护里边的私有变量不受外界的干扰,除了保护私有变量外,还可以存储一些内容,这样的模式叫做闭包。

2、闭包的作用是什么

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。

作用是:通过一系方法,将函数内部的变量(局部变量)转化为全局变量

3、闭包的用途

闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。 

function f1(){
 var n=999;
 nAdd=function(){
    alert(n+=1);  
  }
 function f2(){
    alert(n);
  }
 return f2;
}
var result=f1();
result(); //999
nAdd();//1000
result(); //1001

在这段代码中,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相当于是一个操控者,可以在函数外部对函数内部的局部变量进行操作。

4、使用闭包的注意点

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

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

使用一

function f1() {
           var a = 0;
           return function () {
               return a+5;
           }
        }

var f=f1();
console.log(f);
//打印结果:打印出来一个函数,而且正好是内层函数
ƒ () {
return a+5;
}

console.log(f());
//打印结果:5

 

 使用二

如果我们碰到这样的例子,我们记住一点,外层函数只要不被调用第二次,那么外层函数的参数或者变量的值就不会被冲刷,也就是说对于内层函数而言,外层函数的变量可以看成“全局变量”。

function f2() {
            var a = 0;
            return function () {
                return a++;//a++称为“后增量”,++a称为“前增量”
            }
        }
        f=f2();
        console.log(f());
        console.log(f());
        console.log(f());
        f=f2();
        console.log(f());
        console.log(f());
        console.log(f());

输出结果为:
0
1
2
0
1
2

例子三

function f3() {
            var a = 0;
            return function () {
                return ++a;
            }
        }

        console.log(f3()());
        console.log(f3()());
        console.log(f3()());
打印结果:

1
1
1

这个例子我们直接用图解来看一下:在这里插入图片描述

 这个不就相当于外层函数调用了3次,所以a也被重置成0三次。

相关文章:

  • 【概率论与数理统计(研究生课程)】知识点总结7(参数估计)
  • 精彩回顾 l Rust唠嗑室:Xline跨数据中心一致性管理
  • vue进阶04-vue文档生成工具vuepress2
  • HDLBits: 在线学习 SystemVerilog(十一)-Problem 60-64
  • Linux环境基础开发工具使用
  • IDEA使用swing创建应用程序
  • 22.0、C语言数据结构——二叉排序树
  • GSW同态加密方案学习
  • Java -- 每日一问:Exception 和 Error 有什么区别?
  • 使用 Typora 画图
  • Gradle 入门说难也不难,说简单吧也不简单~
  • 层次聚类分析及代码实现
  • 学生选课系统 前后端分离 vue springboot
  • 网络安全比赛A模块任务书
  • IP报文在阿里云上的神奇之旅:同地域内云上通信
  • [case10]使用RSQL实现端到端的动态查询
  • 【Leetcode】104. 二叉树的最大深度
  • JavaScript标准库系列——Math对象和Date对象(二)
  • Just for fun——迅速写完快速排序
  • python大佬养成计划----difflib模块
  • tensorflow学习笔记3——MNIST应用篇
  • 初探 Vue 生命周期和钩子函数
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 限制Java线程池运行线程以及等待线程数量的策略
  • 小程序button引导用户授权
  • elasticsearch-head插件安装
  • 我们雇佣了一只大猴子...
  • ​MySQL主从复制一致性检测
  • ​Python 3 新特性:类型注解
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • #define
  • #pragma multi_compile #pragma shader_feature
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • $NOIp2018$劝退记
  • %check_box% in rails :coditions={:has_many , :through}
  • (33)STM32——485实验笔记
  • (C语言)fgets与fputs函数详解
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第5节(封闭类和Final方法)
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (vue)el-checkbox 实现展示区分 label 和 value(展示值与选中获取值需不同)
  • (初研) Sentence-embedding fine-tune notebook
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • (附源码)springboot炼糖厂地磅全自动控制系统 毕业设计 341357
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (论文阅读11/100)Fast R-CNN
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (五)关系数据库标准语言SQL
  • (转)c++ std::pair 与 std::make
  • (转)chrome浏览器收藏夹(书签)的导出与导入
  • .bat批处理(四):路径相关%cd%和%~dp0的区别
  • .net 4.0 A potentially dangerous Request.Form value was detected from the client 的解决方案
  • .net 开发怎么实现前后端分离_前后端分离:分离式开发和一体式发布
  • .Net(C#)常用转换byte转uint32、byte转float等
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地中转一个自定义的弱事件(可让任意 CLR 事件成为弱事件)