(1)知识点
- (1.1)定义
- (1.2)变量的作用域
- (1.3)如何从外部读取局部变量
- (1.4)判断闭包
- (1.5)用途
- (1.6)使用注意点
- (1.7)面试题
(2)细化
(2.1)定义
能够读取其他函数内部变量的函数称之为闭包。
(2.2)变量的作用域
要理解闭包,首先要先理解闭包的作用域:全局变量和局部变量
全局变量:即定义在函数外部的变量
优:反复使用,且共享使用
缺:可能随时在任意位置被篡改——全局污染
局部变量:使用var声明,定义在函数内部的变量
不可反复使用!方法调用完自动释放
函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!
Tips:尽量避免使用全局变量
(2.3)如何从外部读取局部变量
使用闭包,即在函数内部再定义一个函数
function f1(){
var n=999;
function f2(){
alert(n); // 999
}
}
函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的;但是反过来就不行,f2内部的局部变量,对f1就是不可见的。这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。
这个时候只需要将f2作为返回值,那么在外部就可以读取到f1中的变量n了
function f1(){
var n=999;
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
由此,f2函数即形成了闭包。
(2.4)判断闭包
a. 内外层函数嵌套
b. 内层函数必须使用了外层函数的局部变量
c. 外层函数将内层函数返回到外部,可在外部调用
Tips:外层函数调用了几次,就有几个受保护的局部变量副本
(2.5)闭包的作用
a. 可以读取函数内部的变量
b. 使得这些变量的值始终保持在内存中,不会在调用结束后,被垃圾回收机制回收
function f1(){
var n=999;
nAdd=function(){n+=1} //匿名函数
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
nAdd();
result(); // 1000
result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。
(2.6)使用注意点
a. 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
b. 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
(2.7)面试题
function outer(){
for(var i=0,arr=[];i<3;i++){//i受保护的变量
arr[i]=function(){return i};
}//i变成了3
return arr;
}
var funs=outer(); //外层函数调用一次,只有1个i
console.log(funs[0]()); //3
console.log(funs[1]()); //3
console.log(funs[2]()); //3
(3)实践
<script type="text/javascript">
/*定义一个函数,模拟取号机:
每次取一个数
数是连续不重复的
*/
//定义工厂函数保护局部变量
function factory(){
var n=0;//受保护的局部变量
return function(){ return ++n; }
}
//获得返回的内部函数对象
var ccb=factory();//外层函数调用第一次
//ccb:function(){ return ++n; }
//使用内部函数对象操作受保护的变量
console.log(ccb());//1
console.log(ccb());//2
n=1;
console.log(ccb());//3
console.log("----------");
var icbc=factory();//外层函数调用第二次
console.log(icbc());//1
console.log(icbc());//2
console.log("----------");
</script>
参考学习:
学习Javascript闭包 ---- 阮一峰