一、什么是闭包?
- 找一个作用域中可以访问另一个作用域的变量
理解闭包的关键在于:外部函数调用之后其变量对象本应该被销毁,但闭包的存在使我们仍然可以访问外部函数的变量对象,这就是闭包的重要概念。
二、如何产生一个闭包
就是在一个函数内部创建另一个函数
.通常,函数的作用域及其所有变量都会在函数执行结束后被销毁。但是,在创建了一个闭包以后,这个函数的作用域就会一直保存到闭包不存在为止。
//未发生闭包
function fn(){
var n=10;
return n;
}
fn();
//f发生闭包
function fn(){
var n=10;
return function(){
return n;
}
}
var fn1=fn();
console.log(fn1());
延迟函数的生命
二、点击事件使用闭包
- 实例
点击事件对应的索引不一样:两个时间不一样 for是加载就执行 但是点击是点击才执行但是for已经循环完了
<script type="text/javascript">
//1|给li注册点击事件
var hereoes=document.querySelectorAll('li');
for(var i=0;i<hereoes.length;i++){
var li=hereoes[i];
li.onclick=function(){
//2、dianjili的时候输出当前li对应的索引
console.log(i);
}
}
</script>
- 始终是4和预期不一样
- 解决1存起来给每个li添加自己的检索属性
<script type="text/javascript">
//1|给li注册点击事件
var hereoes=document.querySelectorAll('li');
for(var i=0;i<hereoes.length;i++){
var li=hereoes[i];
//记录索引
li.index=i;
li.onclick=function(){
//2、dianjili的时候输出当前li对应的索引
console.log(this.index);
}
}
</script>
- 使用闭包
<script type="text/javascript">
//1|给li注册点击事件
//使用闭包
var hereoes=document.querySelectorAll('li');
for(var i=0;i<hereoes.length;i++){
var li=hereoes[i];
//记录索引
(function (i){
li.onclick=function(){
//2、dianjili的时候输出当前li对应的索引
console.log(i);
}
})(i);
}
</script>
闭包不会立即释放延展作用域
三、定时器应用闭包
console.log('1');
setTimeout(function(){
console.log(2);
},0);
console.log(3);
;(function(){
var a=0;
setInterval(function(){
console.log(a++);
},1000)
})();
</script>
1
3
2
- 先执行执行栈,先把执行栈执行完再执行任务队列
四、闭包缺陷
闭包的缺点就是常驻内存会增大内存使用量,并且使用不当很容易造成内存泄露。如果不是因为某些特殊任务而需要闭包,在没有必要的情况下,在其它函数中创建函数是不明智的,因为闭包对脚本性能具有负面影响,包括处理速度和内存消耗。
五、面试题
function fun(n,o){
console.log(o);
return {
fun:function(m){
return fun(m,n);
}
};
}
//n=0 o=undefined
var a=fun(0);
//undefined
a.fun(1);
//0
a.fun(2);
//0
a.fun(3);
//0
var b=fun(0).fun(1).fun(2).fun(3);//undefined 0 1 2
var c=fun(0).fun(1);//undefined 0
c.fun(2);//1
c.fun(3);//1
- 面试2
var name='1';
var obj={
name:'2',
fn:function(){
return function(){
return this.name;
};
}
};
var fn=obj.fn();
console.log(fn());//1