闭包的概念
在高程三中对闭包的定义是这样的:闭包是指有权访问另一个函数作用域中变量的函数。其实就是函数A返回了一个函数B,并且函数B使用了函数A的变量,函数B就被称为闭包。
function A(){
var a = 'a';
function B(){
alert(a)
}
return B
}
在js中变量的作用域分为两种:全局变量和局部变量
var n = 123;
function fn(){
alert(n)
}
fn(); //123
在函数内部可以直接访问全局变量,但要在外部访问函数内部的变量呢?
function fn(){
var n = 123;
}
alert(n); //n is not defined
可以看到直接报错了,显示n
没有被定义,由于种种原因我们需要得到内部变量,我们可以在函数内部再定义一个函数,然后把这个函数返回出来,这样我们能就可以取到函数内部变量
function fn(){
var n = 123;
function fn2(){
console.log(n)
}
return fn2
}
var result = fn();
result(); //123
在上面代码中fn()的所有局部变量相对于fn2()是可见的,但反过来就不行,fn2()的局部变量对于fn()就是不可见的,如此我们就可以把fn2作为返回值,在fn外部就可以访问fn内部的变量了。
这就是“链式作用域”:子对象可以一级一级的向上寻找所有父对象的变量,所以所有父对象的变量对子对象都是可见的,反之则不行。
闭包的用途
闭包可以被用在很多地方,它最大的用处有两个:一个是上文提到的在函数外部获取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。我们会经常遇到这种情况:
for(var i=0; i <= 5; i++){
setTimeout(function (){
console.log(i)
},1000)
}
首先因为setTimeout()
是个异步函数,所以会先把循环全部执行完毕,这时候i
就等于6了,所以会输出一堆的6.要解决这个问题就要用到闭包:
for (var i=0; i <= 5; i++){
(function (n){
setTimeout(function (){
console.log(n)
},1000)
})(i)
}
其实要解决这个问题还有两种方法,第一种就是使用setTimeout()
的第三个参数
for (var i=0; i <= 5; i++){
setTimeout(function (n){
console.log(n)
},1000,i)
}
还有一种就是使用let
声明变量,let
会创建一个块级作用域
for (let i=0; i <= 5; i++){
setTimeout(function (){
console.log(i)
},1000)
}
使用闭包的注意点
闭包会使函数的变量都保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE浏览器会造成内存泄漏。所以在退出函数之前应把不使用的局部变量清空。
网友评论