JavaScript之闭包

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。
要理解闭包,首先必须理解JS作用域[点击查看]

闭包的概念

在百度百科上是这么解释闭包的:
在这里插入图片描述
其实这个说法是很笼统的。准确来说,闭包是基于正常的垃圾回收处理机制下的。也就是说,一般情况一个函数(函数作用域)执行完毕,里面声明的变量会全部释放,被JS垃圾回收机制回收。但闭包利用一个技巧,让作用域里面的变量,在函数执行完之后依旧保存没有被垃圾回收机制处理掉。
下面我们先写一个常用的闭包例子:

function person() {
    var num = 1
    return function () {
        return console.log(`刘家军周日在敲代码${num++}`);
    }
}
var doSth = person(); // doSth 现在是一个闭包
doSth();
doSth();

输出:
在这里插入图片描述
我们来分析一下这一段代码,首先执行var doSth = person();那么person就执行了,但是执行完毕之后, 变量num并没有被回收释放,因为返回值里面还等待使用num,所以此时,person虽然执行了,但是person的变量并没有被释放,在return在等待继续使用这些变量了,这个时候doSth就是一个闭包。

你每执行一次doSth,结果就变化一次,这就是闭包的神奇之处,它改变了JS的内存机制。

然后我们再看看长得很像闭包的形式

function person() {
      var num = 1
    function doSth() {
        console.log(`刘家军周日在敲代码${num++}`);
    }
    doSth()
}
person();
person();

输出:
在这里插入图片描述
如果按照百度上所说的闭包可以读取其他函数内部的变量,person在全局中执行,执行过程中也访问到了num,但他不是闭包,我们来一遍它的执行过程,
函数person执行,执行完之后,再执行的时候,里面的num,doSth函数又重新声明了。那么根本就没有阻止person作用域中的变量被js垃圾回收机制所回收,所以就不能叫闭包,所以闭包要是一个定义在函数内部的函数

闭包的特性

我们从上面的例子可以总结出闭包有3个特性:

1.函数嵌套函数
2.函数内部可以引用函数外部的参数和变量
3.参数和变量不会被垃圾回收机制回收
再来看一个经典例子-定时器与闭包:
   for(var i = 0; i < 5; i++){
        setTimeout(() =>{
            console.log(i)
        },100)
    }

输出:
在这里插入图片描述
结果输出5次5,因为js是单线程的,所以在执行for循环的时候定时器setTimeout被安排到任务队列中排队等待执行,而在等待过程中for循环就已经在执行,等到setTimeout可以执行的时候,for循环已经结束,i的值也已经编程5,所以打印出来五个5,如果对这一点还不是很清楚的可以看一下我前面所写的关于JS异步系列的文章
那么我们为了实现输出0,1,2,3,4修改下代码,由于在ES5中没有块级作用域的说法,所以得利用函数自己创建一个作用域(如果把for循环里面的var变成let,也能实现预期结果)

for(var i = 0; i < 5; i++){
     (function(j){    // 传入参数j j = i
        setTimeout(() =>{
          console.log(j) 
     },100)
     })(i)
}

输出:
在这里插入图片描述
这哪又用到了闭包我们分析下,for循环每一次都执行一个 匿名自执行函数,每一次变量 i 被当做参数传到匿名自执行函数中去 , 那么这个匿名自执行函数中创建了一个变量,延时定时器里面需要用到这个参数 j ,但是因为js异步操作,被添加到任务队列中, 那么这个遍历 j 就没有被清理 , 就一直被保存着 , 每一个匿名自执行函数都做一样的事情 , 所以这个时候就产生了闭包 , 变量 j 并没有被回收,依然在等待你使用。

闭包的优缺点

从上面所说的我们可以总结下闭包的优缺点

优点

1.保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突
2.在内存中维持一个变量,可以做缓存
3.匿名自执行函数可以减少内存消耗

缺点

1.其中一点上面已经有体现了,就是被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null;
2.其次由于闭包涉及跨域访问,所以会导致性能损失,我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响

闭包与this的指向

直接上代码:

var name = "window"  // 这是全局的
var obj = {
    name: "obj",  // 这是局部的
    func: function(){
    // 这里是对象内的方法,这里this指向obj
     return function(){
     // 这里是闭包,this指向window,所以this.name就是window.name
     return  console.log(this.name)
   }
   }
}		
var test = obj.func()
test()

输出:
在这里插入图片描述
闭包中的this指向的是window对象,this.name=window. name;
如果要改变闭包中的this有两种方法;
1.因为对象内的方法里的this指向这个对象,所以可以再func里定一个变量self代替this,闭包里this. name改为self. name
2.使用call方法,test.call(obj),不了解call的应用的可以看我之前的文章

关于闭包我就讲到这了,明天我们再详细讲解下js中的this指向

友情链接:点击查看 JavaScript作用域、闭包、this指向系列文章目录

友情链接:点击查看所有文章目录

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
闭包JavaScript中一个重要且强大的概念。它指的是函数能够访问自己定义范围之外的变量,并且这些变量在函数执行完毕后仍然可以被访问到。闭包的应用场景很广泛,它可以用来创建私有变量、实现模块化、延迟执行等等。了解和掌握闭包对于理解JavaScript语言的本质,以及提高代码的可维护性和灵活性都非常有帮助。 从技术的角度来看,所有的JavaScript函数都可以被看作是闭包。因为在函数内部,它们可以访问在函数定义范围之外的变量。这也是为什么在JavaScript中,函数可以在定义之后仍然可以访问外部的变量。 总结起来,闭包JavaScript中一个非常重要的概念,它能够让函数访问自己定义范围之外的变量,并且这些变量在函数执行完毕后仍然可以被访问到。了解闭包可以帮助我们更好地理解JavaScript语言的本质,并且提高代码的可维护性和灵活性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [深入理解JavaScript闭包](https://blog.csdn.net/qq_54384868/article/details/130182961)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [JavaScript深入之闭包](https://blog.csdn.net/TZOF_/article/details/117048674)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘家军

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值