js中的闭包

JS中的闭包

什么是闭包?

维基百科定义:
闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures);
是在支持 头等函数 的编程语言中,实现词法绑定的一种技术;
闭包在实现上是一个结构体,它存储了一个函数和一个关联的环境(相当于一个符号查找表);
闭包跟函数最大的区别在于,当捕捉闭包的时候,它的 自由变量 会在捕捉时被确定,这样即使脱离了捕捉时的上下文,它也能照常运行;
MDN对javascript的闭包解释:
根据MDN的定义,闭包就是一个函数和对其周围状态的引用捆绑在一起,这样的组合就叫做闭包

自己的理解:

一个普通的函数,如果它可以访问外层作用域的自由变量,那么这个函数就是一个闭包。

实例一

function markAddr(count) {
	function inner(num) {
		return count + num;
	}
	return inner
}
var add10 = markAddr(10)
console.log(add10(5))

闭包的的执行过程

在了解闭包的执行过程前,我们先要了解js引擎的一些运行原理:
js引擎在执行代码前,会在堆内存中创建一个全局对象:Global Object(GO),该对象 所有的作用域(scope)都可以访问; 里面会包含Date、Array、String、Number、setTimeout、setInterval等等;其中还有一个window属性指向自己。
js引擎在执行到一个函数时,会先创建一个函数对象,存放函数作用域及函数执行体,然后会根据函数体创建一个函数执行上下文,(Functional Execution Context,简称FEC),它包括三部分内容:

  1. 第一部分:在解析函数成为AST树结构时,会创建一个Activation Object(AO): AO中包含形参、arguments、函数定义和指向函数对象、定义的变量;
  2. 第二部分:作用域链:由VO(在函数中就是AO对象)和父级VO组成,查找时会一层层查找;
  3. 第三部分:this绑定的值
    那么当我们执行上面例子里面的闭包时,先将markAddr函数执行完毕,整成情况下会释放AO对象,但是由于markAddr返回了一个函数,这个函数就指向了markAddr函数的AO对象,导致其作用域仍然存在,如此形成了闭包的现象。

闭包的应用:

闭包在js中应用广泛,比如在for循环中遍历点击(onclick事件),由于for循环时立即执行的,而点击事件则是触发,所以直接取i的值只会是最后一个。这种情况下,解决的办法一种方法是存贮i的值,第二种方法则是利用闭包,使每次循环都会创建一个闭包函数。

  • 使用闭包前:

遍历点击事件

  • 使用闭包后:
    哈哈哈哈哈

闭包的隐患及解决办法:

闭包会导致内存泄漏,因为被引用的对象无法释放,就会导致占用内存越来越大,从实例一来讲,由于执行完"var add10 = markAddr(10)"后,add10指向了inner函数生成的函数对象地址,而该函数的作用域又指向了markAddr,从而在markAddr在执行完毕后,也没有释放掉内存占用,这样就导致这些内存一直无法被释放,我们称之为内存泄漏。解决方法是将例子中的add10变量置为null,这样它对markAddr的引用就不存在了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值