闭包就是能够读取其他函数内部变量的函数。由于在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。(引用了自由变量的函数)
function f1(){
var a=10;
var b=20;
function f2(){
console.log(a);
}
f2();
}
f1()
即使跳出了创造自己本身的空间也依然能够访问得到父函数的词法环境
function f1(){
var a=10;
var b=20;
return function f2(){
console.log(b);
}
}
var result=f1();
result();
并没有使用父级函数的变量(词法环境里面的东西),不会产生闭包
function f1(){
var m=10;
function f2(){
console.log('111');
}
f2();
}
f1()
使用父级的父级的变量也会产生闭包(作用域链的关系)
function f1(){
var m=10;
function f2(){
var n=20;
function f3(){
console.log(m)
}
f3()
}
f2()
}
f1()
闭包的本质实际就是Js支持函数里面嵌套函数,和作用域链机制
闭包的优势:
1.减少全局变量(闭包会捕获自己需要使用的父级变量,保存起来,函数执行完后并不会马上销毁)
function f(){
var a=0;
return function(){
a++;
alert(a);
}
}
var result=f();
result(); //1
result(); //2
result(); //3
result(); //4
2.减少传递给函数的参数数量
业务逻辑:base为基数,max为最大值(基数+...+最大值)
function calFactory(base){
return function(max){
var total=0;
for(var i=base;i<=max;i++){
total=total+i;
}
alert(total)
}
}
var result=calFactory(0);
result(5);
3.封装
(function(){
var m=0;
function getM(){
return m;
}
function setM(val){
m=val;
}
window.getM=getM;
window.setM=setM;
})()
setM(12);
alert(getM());;
使用闭包的注意点:
1.对捕获的变量只是引用,不是复制
function f(){
var num=1;
function g(){
alert(num);
}
num++;
g()
}
f(); //2
2.父级函数每调用一次会产生不同的闭包
function f(){
var num=1;
return function(){
num++;
alert(num);
}
}
var result=f();
result(); //2
result(); //3
var result2=f();
result2(); //2
3.循环中的问题
//假设页面存在3个div,此时点击div全部弹3,因为i是一个全局变量
var oDiv=document.getElementsByTagName('div');
for(var i=0;i<oDiv.length;i++){
oDiv[i].onclick=function(){
alert(i);
}
}
//通过闭包解决,匿名函数每调用一次就会产生一个词法环境,3次即时调用,产生3个词法环境
oDiv=document.getElementsByTagName('div');
for(var i=0;i<oDiv.length;i++){
oDiv[i].onclick=(function(g){
return function(){
alert(g)
}
})(i)
}