js闭包循环原因_关于闭包的理解

3bdaa9914a6cefac05371cdb6f531504.png

以前我只知道函数套函数就是闭包,还听说闭包存在内存泄露,如今细细深究,这牵扯的东西真多,怪不得面试官这么重视。。比如闭包会涉及到作用域,作用域链,函数执行环境,匿名函数,内存,性能优化等。。还都是一些重量级的东西,彻底懂闭包说明你对js有很深的造诣,不过本文不着重说这些很术语的东西,书上网上已经很多了,不过可能一下子也看不懂,相信看到本文能让你对闭包有更好的理解。

1.什么是闭包?

2.为什么使用闭包?

3.如何使用闭包?

4.何时使用闭包?

5.为什么慎用闭包?

6.闭包与内存泄露有关系?

什么是闭包

#MDN的解释:闭包是函数和声明该函数的词法环境的组合。

#javascript高程三的定义:闭包是指有权访问另一个函数作用域中的变量的函数。

#简单说:如果一个函数,使用了它范围外的变量,那么【这个函数+这个变量】就叫做闭包

#复杂说:函数1里面再套一个函数2,最终return函数2,函数2用到函数1的变量。当调用函数1时,函数2在作用域链中搜索变量a,最终在函数1找到并执行相应程序。一般来说,函数执行完之后,局部活动对象(变量a)会被销毁,但闭包又有所不同。即使函数1执行完也不会被销毁,因为函数2执行时已经将变量a引入自己的作用域链,所以a会一直在内存中,直到函数2被销毁。所以,这也就是慎用闭包的原因(比普通函数占用更多的内存)。

function 

一个很经典的闭包反例:

function 

这个函数返回一个函数数组,表面上看,每一项都打印自己的索引值,但实际都是5。因为每个函数的作用域链都引用着i(注意,i是函数fn内定义的),也就是同一个i,当fn()返回res后,i就是5了,所以每次打印前i已经是5了,只是内部函数没有执行看不到而已。

解决这个问题有两种办法:

(一)创建一个匿名函数强制让闭包符合预期

function 

这里将i的当前值复制给num并立即执行,里面实际上又创建了个闭包(因为匿名函数内访问了外部变量num)引用着num,类似副本的作用,因此每次打印各自的值。

(二)let 的块级作用域

function 

let 不同于 var 在于 let存在块级作用域,每次创建一个新的i,而var是全局的,只有一个。

为什么使用闭包

闭包是一种重用一个变量,又保护变量不被污染的机制。

全局变量和局部变量都具有不可兼得的优缺点。

  • 全局变量: 优: 可重用, 缺: 易被污染
  • 局部变量: 优: 仅函数内可用,不会被污染,缺: 不可重用

如何使用闭包

1. 用外层函数包裹要保护的变量和内层函数。

2. 外层函数将内层函数返回到外部。

3. 调用外层函数,获得内层函数的对象,保存在外部的变量中——形成了闭包。

何时使用闭包

1.凡是用到回调的地方,都可能有闭包。

回调:被当做参数的函数就是回调,同步回调(forEach,sort),异步回调(setTimeout,setInterval)

回调不会立即执行,要么用户触发执行,要么浏览器触发执行,是的,有时候调用一个函数并不需要它立即执行。

(一)javascript是事件驱动型的,绑定函数触发事件,这里绑定函数可以理解为调用一个回调,addEventListener()的第二个参数就是一个函数

这里区分一下DOM0,DOM2的事件处理程序,DOM0是将函数赋值给事件处理程序属性 ,DOM2将函数作为参数,都是为了未来的某个时间执行,DOM2是DOM0的重写版本,所以DOM0是隐式回调。

比如切换标签卡,链接

function 

比如切换页面字号:链接

function 

2.setTimeOut 与 setIterval 的第一个参数就是函数

比如:5秒后改变指定元素样式

function 

比如每隔5秒打印一次当前值(或者进行一些操作):

function 

3. 重构数组方法 sort

比如 根据对象某一属性排序

function 

(二)封装相关功能集

封装一系列具有相关功能的方法供使用

闭包的本意就是将数据对象和操作它的方法关联(包)起来,基于这样的原理,使用闭包就加强了函数的封装性。

比如封装localStorge

function 

(三) 模拟私有方法

比如 日期格式化为 xxxx-xx-xx xx:xx:xx

function 

为什么慎用闭包

闭包形成的原因是外层函数调用后,外层函数的函数作用域对象无法释放,被内层函数引用着,无法自动释放内存。

闭包与内存泄露没有关系

我并没有在js高程三和MDN或者阮一峰老师的文章中看到闭包会导致内存泄露的问题,只说到由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。是IE的问题,IE不能回收,不是闭包的问题,闭包只是占内存多而已。

内存泄漏的概念:不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak),参考:JavaScript 内存泄漏教程

内存泄漏是指你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问,而系统也不能再次将它分配给需要的程序。

【不再用到】:可是我们明明需要外部作用域的变量!

【无法访问】:虽然无法直接访问,但可以间接访问啊!

基于以上:闭包与内存泄露无关。

总结:闭包无处不在,可能你用了但是不知道那就是闭包。

Appendix:

方应杭:「每日一题」JS 中的闭包是什么?

MDN:闭包

阮一峰:

http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html

end~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值