非付费用户可前往公众号“前端基地”进行免费阅读,文章链接如下:
深入解析JavaScript闭包:介绍、条件、常见示例与应用
目录
闭包介绍
闭包的定义:
闭包(Closure)在程序语言中是一种特定的语法结构,其特点在于:一个函数和对其周围状态(lexical environment)的引用捆绑在一起(或者说闭包让你可以访问到一个外部函数的作用域)。简言之,当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(或函数)时,就形成了闭包。
闭包的作用:
延长外部函数局部变量的生命周期:即使外部函数已经执行结束,其内部的变量依然能存留在内存中,因为闭包持有对这些变量的引用。
数据封装和私有化:闭包可以创建私有变量和方法,因为外部无法直接访问闭包内部的变量。
函数工厂:闭包允许我们创建参数化的函数,即可以根据不同的参数生成不同的函数。
闭包的生命周期:
闭包在嵌套内部函数定义时产生(而非在调用时),其生命周期至少与嵌套的内部函数一样长。当内部函数成为垃圾对象时(即没有任何引用指向它时),闭包的生命周期也随之结束。
闭包的优缺点:
优点:不产生全局变量,有助于避免全局命名空间的污染。实现属性私有化,提供数据封装。允许创建函数工厂,生成参数化的函数。
缺点:内存占用:由于闭包持有对外部函数变量的引用,这些变量不会被及时释放,可能导致内存占用增加。内存泄漏风险:如果闭包被不当地持有(例如,被全局变量引用),可能导致内存泄漏。
解决方法:在不需要闭包时,应及时释放对闭包的引用,例如将引用闭包的变量置为 null。避免在循环中创建大量的闭包,因为每个闭包都会持有对外部变量的引用,可能导致内存占用急剧增加。
示例代码:由于 var 的变量提升和循环的闭包特性,所有按钮的点击事件都会打印出最后一个索引值。而在使用闭包的示例中,每个按钮的点击事件都会打印出正确的索引值,因为每个闭包都持有对各自索引值的引用。
<!-- 传统方法,所有按钮点击都会打印最后一个索引值 -->
<body>
<button>菜单一</button>
<button>菜单二</button>
<button>菜单三</button>
<script>
var btn = document.getElementsByTagName('button');
&n