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

闭包的简单讲解

什么是闭包

要理解闭包,首先来看下下面这段代码:

var count = 1;function add(){count++;console.log(count);
}add(); // 2
add(); // 3
add(); // 4

可以看到这里调用了3次函数,count的值也从1增长到了4,但是这么写会导致全局变量被污染,所以将count的定义移动到add函数内部,代码如下:

function add() {var count = 1;count++;console.log(count);
}add(); // 2
add(); // 2
add(); // 2

但是这又导致了另一个问题,变为局部变量的count不会自增了,所以那么就可以利用闭包的这个特性将每次调用时的count保存起来这样就可以实现变量的自增了,代码如下:

function add() {var count = 1;return function(){count++;console.log(count);}
}let getCount= add();
getCount(); // 2
getCount(); // 3
getCount(); // 4

可以这样理解,通过将add函数赋值给getCount这个变量,可以看作如下代码

let getCount= function(){count++;console.log(count);
}

每当调用getCount()函数的时候,首先要获取count变量,因为JavaScript中存在作用域链的关系,所以会从add函数下得到对应的count,因为闭包存在着闭包可以访问到父级函数的变量,且该变量不会销毁的特性所以上次的变量会被保留下来,所以可以做到自增的实现。

闭包的特性

根据以上对闭包的讲解,我们可以总结出闭包的特性

  1. 闭包可以访问到父级函数的变量

  2. 访问到父级函数的变量不会销毁

闭包的用途

1.封装私有变量

闭包可以用于封装私有变量,以防止其被外部访问和修改。封装私有变量可以一定程度上防止全局变量污染,使用闭包封装私有变量可以将这些变量限制在函数内部或模块内部,从而减少了全局变量的数量,降低了全局变量被误用或意外修改的风险。

function add(){let count = 0function a(){count++console.log(count);}return a
}
var res = add() 
res() //1 
res() //2
res() //3

在上面的代码示例中,add函数返回了一个闭包a,其中包含了count变量。由于count只在add函数内部定义,因此外部无法直接访问它。但是,由于a函数引用了count变量,因此count变量的值可以在闭包内部被修改和访问。这种方式可以用于封装一些私有的数据和逻辑。

2.做缓存

函数一旦被执行完毕,其内存就会被销毁,而闭包的存在,就可以保有内部环境的作用域。

function foo(){var myName ='张三'let test1 = 1const test2 = 2 var innerBar={getName: function(){console.log(test1);return myName},setName:function(newName){myName = newName}}return innerBar
}
var bar = foo()   
console.log(bar.getName()); //输出:1 张三
bar.setName('李四')
console.log(bar.getName()); //输出:1 李四

这里var bar = foo() 执行完后本来应该被销毁,但是因为形成了闭包,所以导致foo执行上下文没有被销毁干净,被引用了的变量myName、test1没被销毁,闭包里存放的就是变量myName、test1,这个闭包就像是setName、getName的专属背包,setName、getName依然可以使用foo执行上下文中的test1和myName。

闭包的缺点

闭包会导致变量不会被垃圾回收机制回收,造成内存消耗以及对于不恰当的使用闭包可能会造成内存泄漏的问题

如果不是某些特定任务需要使用闭包,在其它函数中创建函数是不明智的,因为闭包在处理速度和内存消耗方面对脚本性能具有负面影响。

内存泄漏的解决方案

this.name = 'WindowName'
let myObj = {name: 'beast senpai',get: function(){return function(){console.log(this); // WindowNamereturn this.name;}}
}let myObjname = myObj.get()();//先调用 myObj.get(),再调用它返回的结果
console.log(myObjname); // WindowName

这里发生了内存泄漏使得this指向了Window对象

解决方案1:在get函数使用that保存此时的this

this.name = 'WindowName'
let myObj = {name: 'beast senpai',get: function(){let that = this;return function(){console.log(that); // myObjreturn that.name;}}
}let myObjname = myObj.get()();
console.log(myObjname); // beast senpai

解决方案2:将get函数的返回值改回使用箭头函数的方式做返回

this.name = 'WindowName'
let myObj = {name: 'beast senpai',get: function(){return ()=>{console.log(this); // myObjreturn this.name; }}
}let myObjname = myObj.get()();
console.log(myObjname); // beast senpai

消除闭包

不用的时候解除引用,避免不必要的内存占用

取消fn对外部成员变量的引用,就可以回收相应的内存空间。

function add() {var count = 0return function fn() {count++console.log(count)}
}var a = add() // 产生了闭包
a() // 1
a() // 2
a = null // 取消 a 与 fn 的联系,这个时候浏览器回收机制就能回收闭包空间

参考

JavaScript | 闭包

什么是闭包?(详解闭包)

http://www.dtcms.com/a/361935.html

相关文章:

  • 三、数据结构
  • VMware安装
  • 基于docker-compose搭建EFK(Elasticsearch+fluentd+kibana)的日志平台
  • 【高等数学】第十章 重积分——第五节 含参变量的积分
  • python3中的除法/ (会把int变成float)向下取整//(不会改变int类型) 和 直接舍弃小数,向0截断
  • JVM性能监控工具的使用
  • python中的分代垃圾回收机制的原理【python进阶二、2】
  • 基于uni-app的校园综合服务平台开发实战
  • uni-app支持单多选、搜索、查询、限制能否点击组件
  • 掌握CRISPE框架:结构化提示词设计的终极指南
  • 【溜冰场轮滑计时计费扣次软件有哪些?】分享常见的几款软件,佳易王软件系列#软件功能解析操作教程
  • Tiny RDM:一个现代化轻量级的Redis桌面客户端
  • 盟接之桥说制造:浅谈本分和做正确的事情
  • 前端微前端架构深度实践:从单体应用到微前端的完整架构解决方案
  • 携程旅行 web 验证码 分析
  • GET、POST、添加、编辑
  • python爬虫之selenium库进阶(小白五分钟从入门到精通)
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(23):文法+单词第7回5+考え方3
  • 为什么要使用RocketMQ半消息
  • 使用C#语言 基于FTP协议进行文件夹上传下载
  • 【Android】Span富文本简介
  • 苹果 Safari 地址栏可能被超大光标视觉欺骗
  • 阿里云OSS架构示意图与流程
  • AR眼镜在警务安防的应用方案
  • 前沿科技竞速:脑机接口、AI芯片与半导体生态上的新突破
  • 线性回归中梯度下降与正规方程以及拟合问题与正则化
  • 【职业】算法与数据结构专题
  • 【Flink】DataStream API (二)
  • 收藏!VSCode 开发者工具快捷键大全
  • 计算机毕设推荐:基于python的农产品价格数据分析与预测的可视化系统的设计与实现 基于Python农产品管理系统【源码+文档+调试】