什么是闭包?(详解闭包)
一、闭包的概念
二、怎么实现闭包
闭包是指一个函数可以访问它定义时所在的词法作用域以及全局作用域中的变量。在JavaScript中,闭包可以通过函数嵌套和变量引用实现
function outerFunction() {
let outerVariable = '我在outer函数里!'; function innerFunction() {
console.log(outerVariable); } return innerFunction; } const innerFunc = outerFunction(); innerFunc(); // 输出: 我在outer函数里!
讯享网
在上面的代码示例中,innerFunction引用了outerVariable,因此JavaScript引擎会保留outerFunction的作用域链,以便innerFunction可以访问outerVariable。
讯享网function a(){
function b(){
var bb = 888 console.log(aa); //输出:666 } var aa = 666 return b } var demo = a() demo()
在上面的代码示例中,a函数定义了一个名为aa的变量和一个名为b的函数,b函数引用了aa变量,因此JavaScript引擎会保留a函数的作用域链,b函数可以访问a函数的执行上下文,b函数内用到了外部函数a的变量aa,在a函数调用结束后该函数执行上下文会销毁,但会保留一部分留在内存中供b函数使用,这就形成了闭包。
具体来说,当内部函数引用外部函数的变量时,外部函数的作用域链将被保留在内存中,以便内部函数可以访问这些变量。
这种函数嵌套和变量共享的方式就是闭包的核心概念。当一个函数返回另一个函数时,它实际上返回了一个闭包,其中包含了原函数定义时的词法作用域和相关变量。
三、闭包的用途
1.封装私有变量
闭包可以用于封装私有变量,以防止其被外部访问和修改。封装私有变量可以一定程度上防止全局变量污染,使用闭包封装私有变量可以将这些变量限制在函数内部或模块内部,从而减少了全局变量的数量,降低了全局变量被误用或意外修改的风险。
在下面这个例子中,调用函数,输出的结果都是1,但是显然我们的代码效果是想让count每次加一的。
function add() {
let count = 0; count++; console.log(count); } add() //输出1 add() //输出1 add() //输出1
一种显而易见的方法是将count提到函数体外,作为全局变量。这么做当然是可以解决问题,但是在实际开发中,一个项目由多人共同开发,你不清楚别人定义的变量名称是什么,这么做有点冒险,有什么其他的办法可以解决这个问题呢?
讯享网function add(){
let count = 0 function 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 = 1 const 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。
3. 模块化编程(实现共有变量)
闭包还可以用于实现模块化编程。模块化编程是一种将程序拆分成小的、独立的、可重用的模块的编程风格。闭包可以用于封装模块的私有变量和方法,以便防止其被外部访问和修改。例如:
讯享网const myModule = (function() {
let privateVariable = '我是私有的!'; function privateMethod() {
console.log(privateVariable); } return {
publicMethod: function() {
privateMethod(); } }; })(); myModule.publicMethod(); // 输出: 我是私有的!
在上面的代码示例中,myModule实际上是一个立即执行的匿名函数,它返回了一个包含publicMethod的对象。在函数内部,定义了一个私有变量privateVariable和一个私有方法privateMethod。publicMethod是一个公共方法,它可以访问privateMethod,但是无法访问privateVariable。这种方式可以用于实现简单的模块化编程。
四、闭包的缺点
闭包也存在着一个潜在的问题,由于闭包会引用外部函数的变量,但是这些变量在外部函数执行完毕后没有被释放,那么这些变量会一直存在于内存中,总的内存大小不变,但是可用内存空间变小了。 一旦形成闭包,只有在页面关闭后,闭包占用的内存才会被回收,这就造成了所谓的内存泄漏。
因此我们在使用闭包时需要特别注意内存泄漏的问题,可以用以下两种方法解决内存泄露问题:

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/31274.html