js中的闭包

js中的闭包,第1张

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),它包括三部分内容:

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

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

使用闭包前:

使用闭包后:
闭包的隐患及解决办法:

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

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1297106.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-10
下一篇 2022-06-10

发表评论

登录后才能评论

评论列表(0条)

保存