目录

  • 一、闭包定义
  • 二、闭包的特点
  • 三、闭包原理
  • 四、闭包的应用场景。
  • 五、闭包的优点和缺点

一、闭包定义

函数执行后返回的结果是一个内部函数,并被外部变量所引用,如果内部函数持有被执行函数作用域的变量,则形成了闭包。

闭包举例:

function add(){var a=0;return function add1(){a++;console.log(a);}
}
const res = add();
//调用3次函数
res();
res();
res();
//1 2 3

二、闭包的特点

  1. 函数嵌套函数
  2. 内部函数可以访问外部函数的参数和变量
  3. 参数和变量不会被垃圾回收机制回收

三、闭包原理

函数执行会分成两个阶段(预编译阶段和执行阶段)。

  • 预编译阶段:如果发现内部函数使用了外部函数的变量,就会在内存中创建一个“闭包”对象并保存对应的变量值,如果已经创建了闭包则只需要增加对应的属性值即可。
  • 执行阶段:执行完成后,函数的执行上下文会被销毁,函数对“闭包”对象的引用也会被销毁,但是其内部函数还持有该“闭包”的引用,所以内部函数可以继续使用“外部函数”中的变量。

闭包引用了函数作用域链的特性,一个函数内部定义的函数会将包含外部函数的活动对象添加到它的作用域链中,函数执行完毕后,其执行作用域链被销毁,但因内部函数的作用域链仍然在引用这个活动对象,所以其活动对象不会被销毁,直到内部函数被销毁后活动对象才会被销毁。

四、闭包的应用场景。

  1. 模块封装,在各模块规范出现之前,都是用这样的方式防止变量污染全局。
    举例:
var A = (function () {// 这样声明为模块私有变量,外界无法直接访问到,避免了变量污染全局var x = 0;function A() { };A.prototype.a = function a(){return x;}return A;
}())
console.log(A)//[Function: A]
  1. 在循环中创建闭包,防止取到意外的值。
    举例:数组 helpText 中定义了三个有用的提示信息,每一个都关联于对应的文档中的input 的 ID。通过循环这三项定义,依次为相应input添加了一个 onfocus 事件处理函数,以便显示帮助信息。
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><p id="help">Helpful notes will appear here</p><p>E-mail: <input type="text" id="email" name="email"></p><p>Name: <input type="text" id="name" name="name"></p><p>Age: <input type="text" id="age" name="age"></p><script>function showHelp(help) {document.getElementById('help').innerHTML = help;}function setUpHelp() {var helpText = [{ 'id': 'email', 'help': 'Your e-mail address' },{ 'id': 'name', 'help': 'Your full name' },{ 'id': 'age', 'help': 'Your age (you must be over 16)' }]for (let i = 0; i < helpText.length; i++) {let item = helpText[i];// onfocus事件,对象聚焦时发生document.getElementById(item.id).onfocus = function(){showHelp(item.help)}}}setUpHelp();     </script>
</body></html>

运行这段代码后,会发现并没有达到想要的效果。无论焦点在那个input上,显示的都是关于年龄的提示信息。
造成这样的结果的原因是:赋值给onfocus的是闭包。这些闭包是由他们的函数定义和在setUpHelp作用域中捕获的环境所组成的。这三个闭包在循环过程中被创建,但是他们共享了同一个词法作用域,这个作用域存在一个变量item。因为变量item是var声明的,由于变量提升,所以具有函数作用域。当onfocus的回调执行时,item.help的值被决定。由于循环在事件触发前就早已执行完毕,变量对象item(被三个闭包所共享)已经指向了helpText的最后一项。

解决以上问题的方法之一就是使用更多的闭包:

// 第一种解决方案 使用更多的闭包function showHelp(help) {document.getElementById('help').innerHTML = help;}// 使用多一个闭包function makeHelpCallback(help){return function(){showHelp(help)}}function setUpHelp() {var helpText = [{ 'id': 'email', 'help': 'Your e-mail address' },{ 'id': 'name', 'help': 'Your full name' },{ 'id': 'age', 'help': 'Your age (you must be over 16)' }]for (let i = 0; i < helpText.length; i++) {var item = helpText[i];// onfocus事件,对象聚焦时发生document.getElementById(item.id).onfocus = makeHelpCallback(item.help)}}setUpHelp();

这一段代码可以如我们所期望的那样工作。所有的回调不再共享同一个环境,makeHelpCallback函数为每一个回调创建了一个新的词法环境。在这些环境中,help指向helpText数组中对应的字符串。

第二种解决办法:使用匿名闭包

 //第二种解决方法:匿名闭包function showHelp(help) {document.getElementById('help').innerHTML = help;}function setUpHelp() {var helpText = [{ 'id': 'email', 'help': 'Your e-mail address' },{ 'id': 'name', 'help': 'Your full name' },{ 'id': 'age', 'help': 'Your age (you must be over 16)' }]for (let i = 0; i < helpText.length; i++) {(function(){var item = helpText[i];// onfocus事件,对象聚焦时发生document.getElementById(item.id).onfocus = function(){showHelp(item.help)}})();// 马上把当前循环项的item与事件的回调相关联}}setUpHelp();

第三种解决办法:不用闭包,直接使用let关键词声明helpText,不会出现变量提升,且为每个闭包都绑定了相应的块级作用域。

//第三种解决方法:var改成let,没有了变量提升function showHelp(help) {document.getElementById('help').innerHTML = help;}function setUpHelp() {var helpText = [{ 'id': 'email', 'help': 'Your e-mail address' },{ 'id': 'name', 'help': 'Your full name' },{ 'id': 'age', 'help': 'Your age (you must be over 16)' }]for (let i = 0; i < helpText.length; i++) {let item = helpText[i];// onfocus事件,对象聚焦时发生document.getElementById(item.id).onfocus = function(){showHelp(item.help)}}}setUpHelp();

五、闭包的优点和缺点

优点:

  • 内部函数可以访问外部函数作用域中的变量,且访问到的变量长期驻扎在内存中,可供以后使用。
  • 创建变量的私有空间,防止变量污染全局

缺点:

  • 对内存消耗有负面影响。因内部函数保存了对外部变量的引用,导致无法被垃圾回收机制回收,增大了内存的使用量,所以使用不当会导致内存泄漏。
  • 对处理速度具有负面影响。闭包的层级决定了引用的外部变量在查找时经过的作用域链长度。
  • 可能获取到意外的值。

闭包的定义,原理,应用场景,优点,缺点相关推荐

  1. 什么是闭包?闭包的工作原理、优缺点、使用场景和对页面的影响

    参考博客:http://www.cnblogs.com/cxying93/p/6103375.html 闭包(closure)是javascript的一大难点,也是它的特色.很多高级应用都要依靠闭包来 ...

  2. Redis bitmap、hyperlog、布隆过滤器、RoaringBitmap原理应用场景与日活的统计的具体应用

    传统方案-mysql 缺点: 1.空间占用大 2.统计逻辑复杂,比如 统计最近 30 天用户的累计活跃天(每个用户在 30 天里有 N 天使用 app,N 为 1-30,然后将月活跃用户的 N 天加总 ...

  3. 跨越原理优缺点_jsonp的原理,应用场景,优缺点

    在开发测试中,难免会在不同域下进行跨域操作,出于安全性考虑,浏览器中的同源策略阻止从一个域上加载的脚本获取或者操作 另一个域下的文档属性,这时需要进行跨域的方式进行解决,如:使用jsonp ,ifra ...

  4. Python——特点(优点缺点)

    Python--特点(优点&缺点) Python 是一种面向对象的.解释型的.通用的.开源的脚本编程语言,它之所以非常流行,我认为主要有三点原因: Python 简单易用,学习成本低,看起来非 ...

  5. 数据库索引的作用和优点缺点

    原文:数据库索引的作用和优点缺点 为什么要创建索引呢?这是因为,创建索引可以大大提高系统的性能.  第一,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性.  第二,可以大大加快 数据的检索速 ...

  6. 横瓜执导众程序员开展大讨论关于C、JAVA及其它主流IT技术使用情况和优点缺点。...

    横瓜执导众程序员开展大讨论关于C.JAVA及其它主流IT技术使用情况和优点缺点. 遥执乾坤(44758121)  18:21:23 mysql据说只能使用一个索引,我这里几乎所有字段都有索引. 但每个 ...

  7. yolov3算法优点缺点_优点缺点

    yolov3算法优点缺点 Naive Bayes: A classification algorithm under a supervised learning group based on Prob ...

  8. 什么是闭包?闭包的作用及应用场景

    文章目录 一.什么是闭包 二.闭包的作用 三.使用闭包的注意点 四.思考题 五.应用场景 参考文章 一.什么是闭包 假设,把下面三行代码放在一个立即执行函数中. 三行代码中,有一个局部变量local, ...

  9. 推荐系统中常用算法 以及优点缺点对比

    推荐系统中常用算法 以及优点缺点对比 2014/09/20 [Martin导读]随着互联网特别是社会化网络的快速发展,我们正处于信息过载的时代.用户面对过量的信息很难找到自己真正感兴趣的内容,而内容提 ...

  10. 【Groovy】闭包 Closure ( 闭包类 Closure 简介 | this、owner、delegate 成员区别 | 静态闭包变量 | 闭包中定义闭包 )

    文章目录 总结 一.静态闭包变量 1.执行普通闭包变量 2.执行静态闭包变量 二. 在闭包中定义闭包 三. 完整代码示例 总结 在闭包中 , 打印 this , owner , delegate , ...

最新文章

  1. 马斯克笑了!元宇宙是个啥?反正我不信!
  2. Coding and Paper Letter(二十)
  3. spring第二冲刺阶段第十三天
  4. linux 文件夹的颜色代表什么意思
  5. 在Power BI Desktop报告中使用图像
  6. BZOJ 1822 Frozen Nova 霜冻新星
  7. HTML5 — 知识总结篇《III》【文本元素】
  8. 3DMax人物动画制作
  9. linux卸载phpstudy_phpStudy Linux 面板安装教程
  10. siege压力测试工具
  11. python分割出两幅图像重叠区域代码
  12. 演化模型(evolutionary model) 需求不明确+两次开发(实验开发+产品开发)
  13. spring-mybatis实现注册通过邮箱发送激活码激活注册用户
  14. 解决Chrome浏览器“隐私设置错误,您的链接不是私密连接”
  15. Medical robotics-Regulatory, ethical, and legal considerations for increasing levels of autonomy
  16. 朱松纯:浅谈人工智能:现状、任务、构架与统一 感悟以及部分内容的概括
  17. 联友科技软件测试,联友科技
  18. 企业邮箱给国外发邮件注册哪个好?如何群发邮件?
  19. Flutter仿美团应用开发笔记-首页 (1)
  20. python 一组数据 正态分布散点图_R语言入门之散点图

热门文章

  1. HTML span标签如何居中和右对齐?这里有HTML span标签的样式解析(收藏)
  2. 企业官网模板搭建网站的方法分享
  3. python response.read_Python3基础 response.read 输出网页的源代码
  4. Triangle学习之旅——下载与安装
  5. (spingboot入门案例)SpingBoot整合mybatis(mySql)
  6. UG里的坐标系跟模型的表面不平行,怎么处理?
  7. Vue的数据绑定、Vue的事件绑定、Class和Style的绑定
  8. Flume原理、安装和使用
  9. 自动化测试的分层结构
  10. 2021大同高考成绩查询,2021年大同高考状元是谁分数多少分,历年大同高考状元名单...