这里是修真院前端小课堂,每篇分享文从
【背景介绍】【知识剖析】【常见问题】【解决方案】【编码实战】【扩展思考】【更多讨论】【参考文献】
八个方面深度解析前端知识/技能,本篇分享的是:
【闭包是什么,如何使用?】
1.背景介绍
是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。简单来说,假设函数A在函数B中进行了定义,并且当A在执行时访问了B内部的变量对象,那么B就是一个闭包
2.知识剖析
那么闭包的具体定义是什么呢?当函数可以记住并访问所在的作用域(全局作用域除外)时,就产生了闭包,即使函数是在当前作用域外执行。
这里有几个知识点需要先搞清楚
(1)变量作用域
变量的作用域无非就是两种:全局变量和局部变量。Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。而函数外部不能访问函数内部的局部作用域。这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,实际上声明了一个全局变量
(2)生命周期
函数内部声明的局部变量会随函数的结束而被销毁,即 触发垃圾回收机制
(3)作用域链
作用域链是由当前环境和上层环境的一系变量对象组成,它保证了当前执行环境对符合访问权限的变量和函数的有序访问
我的理解是,但定义在一个函数中的另一个函数被return时就形成了闭包,闭包就是将函数内部和外部连接在一起的一座桥梁。
3.常见问题
以下代码为什么会造成内存泄露?
window.onload = function(){
var el = document.getElementById("id");
el.onclick = function(){
alert(el.id);
}
4.解决方案
内存泄漏的原因:执行这段代码的时候,将匿名函数对象赋值给el的onclick属性;然后匿名函数内部又引用了el对象,存在循环引用,所以不能被垃圾回收机制回收;
修改后的代码:
window.onload = function(){
var el = document.getElementById("id");
var id = el.id; //解除循环引用
el.onclick = function(){
alert(id);
}
el = null; // 将闭包引用的外部函数中活动对象清除
}
5.编码实战
点击按钮会弹出相应的数字0、1、2、3、4
function init({
var pAry = document.getElementsByTagName("button");
for( var i=0; i< pAry.length; i++ ) {
(function(arg){
pAry[i].onclick = function() {
alert(arg);
};
})(i);//调用时参数
}
}
思路:加一层闭包,i以局部变量形式传递给内存函数,在js任务4中的杀人游戏选中的身份死亡有用到。
6.拓展思考
在闭包中的this指向问题
7.参考文献
阮一峰的网络日志:学习Javascript闭包
详细图解作用域链与闭包