闭包是js的一个难点也是它的一个特色,是我们必须掌握的js高级特性,那么什么是闭包呢?它又有什么用呢?

我们都知道,js的作用域分两种,全局和局部,基于我们所熟悉的作用域链相关知识,我们知道在js作用域环境中访问变量的权利是由内向外的,内部作用域可以获得当前作用域下的变量并且可以获得当前包含当前作用域的外层作用域下的变量,反之则不能,也就是说在外层作用域下无法获取内层作用域下的变量,同样在不同的函数作用域中也是不能相互访问彼此变量的,那么我们想在一个函数内部也有限权访问另一个函数内部的变量该怎么办呢?闭包就是用来解决这一需求的,闭包的本质就是在一个函数内部创建另一个函数。

我们首先知道闭包有3个特性:

①函数嵌套函数

②函数内部可以引用函数外部的参数和变量

③参数和变量不会被垃圾回收机制回收

本文我们以闭包两种的主要形式来学习

①函数作为返回值

在这段代码中,a()中的返回值是一个匿名函数,这个函数在a()作用域内部,所以它可以获取a()作用域下变量name的值,将这个值作为返回值赋给全局作用域下的变量b,实现了在全局变量下获取到局部变量中的变量的值

再来看一个闭包的经典例子

一般情况下,在函数fn执行完后,就应该连同它里面的变量一同被销毁,但是在这个例子中,匿名函数作为fn的返回值被赋值给了fn1,这时候相当于fn1=function(){var n = 0 ... },并且匿名函数内部引用着fn里的变量num,所以变量num无法被销毁,而变量n是每次被调用时新创建的,所以每次fn1执行完后它就把属于自己的变量连同自己一起销毁,于是乎最后就剩下孤零零的num,于是这里就产生了内存消耗的问题

再来看一个经典例子-定时器与闭包

写一个for循环,让它按顺序打印出当前循环次数

按照预期它应该依次输出1 2 3 4 5,而结果它输出了五次5,这是为什么呢?原来由于js是单线程的,所以在执行for循环的时候定时器setTimeout被安排到任务队列中排队等待执行,而在等待过程中for循环就已经在执行,等到setTimeout可以执行的时候,for循环已经结束,i的值也已经编程5,所以打印出来五个5,那么我们为了实现预期结果应该怎么改这段代码呢?(ps:如果把for循环里面的var变成let,也能实现预期结果)

引入闭包来保存变量i,将setTimeout放入立即执行函数中,将for循环中的循环值i作为参数传递,100毫秒后同时打印出1 2 3 4 5

那如果我们想实现每隔100毫秒分别依次输出数字,又该怎么改呢?

在这段代码中,相当于同时启动3个定时器,i*100是为4个定时器分别设置了不同的时间,同时启动,但是执行时间不同,每个定时器间隔都是100毫秒,实现了每隔100毫秒就执行一次打印的效果。

②闭包作为参数传递

在这段代码中,函数fn1作为参数传入立即执行函数中,在执行到fn2(30)的时候,30作为参数传入fn1中,这时候if(x>num)中的num取的并不是立即执行函数中的num,而是取创建函数的作用域中的num这里函数创建的作用域是全局作用域下,所以num取的是全局作用域中的值15,即30>15,打印30

最后总结一下闭包的好处与坏处

好处

①保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突

②在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存)

③匿名自执行函数可以减少内存消耗

坏处

①其中一点上面已经有体现了,就是被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null;

②其次由于闭包涉及跨域访问,所以会导致性能损失,我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响

彻底理解js中的闭包相关推荐

  1. 【学习笔记】深入理解js原型和闭包(5)——instanceof

    又介绍一个老朋友--instanceof. 对于值类型,你可以通过typeof判断,string/number/boolean都很清楚,但是typeof在判断到引用类型的时候,返回值只有object/ ...

  2. 【学习笔记】深入理解js原型和闭包(11)——执行上下文栈

    继续上文的内容. 执行全局代码时,会产生一个执行上下文环境,每次调用函数都又会产生执行上下文环境.当函数调用完成时,这个上下文环境以及其中的数据都会被消除,再重新回到全局上下文环境.处于活动状态的执行 ...

  3. 今天来谈谈面试官最喜欢问JS中的闭包问题吧

    今天来谈谈面试官最喜欢问JS中的闭包问题吧 1.什么是闭包? 闭包是指有权访问另外一个函数作用域中的变量的函数,闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在.闭包就是函数的&qu ...

  4. 【学习笔记】深入理解js原型和闭包(9)—— 简述【执行上下文】下

    继续上一篇文章(https://www.cnblogs.com/lauzhishuai/p/10078231.html)的内容. 上一篇我们讲到在全局环境下的代码段中,执行上下文环境中有如何数据: 变 ...

  5. 彻底理解js中this

    相关博文:http://blog.csdn.net/libin_1/article/details/49996815 彻底理解js中this的指向,不必硬背. 首先必须要说的是,this的指向在函数定 ...

  6. 理解js中this的指向

    彻底理解js中this的指向 JavaScript 的 this 指向问题深度解析 转载于:https://www.cnblogs.com/jeacy/p/6509616.html

  7. 从编译器层面理解C#中的闭包的这个坑!

    前言 在公众号上看到一篇文章<正确使用和理解C#中的闭包>,里面提到了闭包的一个坑: 当捕获的外部变量为for循环的迭代变量时,C#认为变量i是定义在循环体外的.所以,当添加委托集合的fo ...

  8. 深入理解Js中的this

    深入理解Js中的this JavaScript作用域为静态作用域static scope,但是在Js中的this却是一个例外,this的指向问题就类似于动态作用域,其并不关心函数和作用域是如何声明以及 ...

  9. js原型和原型链_理解JS中的原型和原型链

    导读:JavaScript中(JS)的原型和原型链是web前端开发面试中经常被问到的问题:同时,如果我们能很好的理解JS中的原型和原型链,对于控制台输出的很多信息我们也能更好的理解,而原型链也是实现继 ...

  10. 理解JS中的声明式与命令式

    理解JS中的声明式与命令式? 声明式编程 :告诉机器你想要的是什么    让机器想出去做 优缺点 : 声明式减少了可变量(Immutable Variable)的声明,程序更为安全,   代码更加简洁 ...

最新文章

  1. 2022-2028年中国床上用品行业投资分析及前景预测报告
  2. codeforce843B Interactive LowerBound
  3. 成为顶尖算法专家需要知道哪些算法?
  4. arthas 排查内存溢出_【spark-tips】spark2.4.0触发的executor内存溢出排查
  5. Docker部署网站之后映射域名
  6. IIS与ASP.NET管道
  7. 您从未听说过的Java 8的10个功能
  8. flutter 生成文档_flutter 如何实现文件读写(使用篇)
  9. 关于 # 符号的使用 - 给 厨师 的回复
  10. php 旋转图片 保存,如何在PHP中旋转并保存图像
  11. spark学习-31-spark2.2.0中Utils.getCallSite()的作用
  12. Linux的/var/www/html目录
  13. 有关字符串的算法(KMP,Manacher,BM)陆续补充
  14. LINUX SHELL获得CPU核心(线程)个数
  15. QT 基础类结构图及核心库
  16. 类风湿性关节炎中的肠-关节轴
  17. 超文本传输协议HTTP
  18. [BZOJ5020] [THUWC 2017]在美妙的数学王国中畅游
  19. 局域网的ROS中设置花生壳
  20. Spring AOP原理及使用,面试必备

热门文章

  1. JavaWeb之servlet详解(转帖)
  2. win7企业版怎么都激活不了,看这里
  3. Centos7 Redis安装
  4. 【数据结构入门】顺序表(SeqList)详解(初始化、增、删、查、改)
  5. fullAvatarEditor富头像上传编辑器
  6. 微信表情包批量导出-2022年8月4日
  7. 记录一次阿里云Mysql 数据库恢复 qp.xb文件恢复数据
  8. WPS如何设置快捷键|为设置颜色添加快捷键
  9. 什么是UML统一建模语言
  10. 【HUST】公选抢课|用Auto.js模拟蹲课过程