在JavaScript中变量分为两种:全局变量和局部变量;顾名思义,全局变量就是定义在全局作用域下面的变量,js中比较特别的地方就在于,全局变量在任何地方都可以直接调用。局部变量就是定义在函数内部作用域下的变量,只能在函数内部被引用。理解闭包首先就要理解嵌套函数的语法作用域的相关规则,看下面一段代码:
var scrop="global";//声明一个全局变量
function checkscrop(){
var scrop="local";//声明一个局部变量
function f(){
return scrop;//在作用域中返回该值
}
return f();
}
var result=checkscrop();//result的值为local
以上代码很容易懂,在函数内部定义一个局部变量,并定义一个函数返回该变量,然后将该函数执行结果返回,现在我们对代码做一点小小的改动
var scrop="global";//声明一个全局变量
function checkscrop(){
var scrop="local";//声明一个局部变量
return function(){
return scrop;
}//返回一个函数对象
}
var result=checkscrop()();//result的值为local
两次返回的结果都是local,表面上看两段代码没有什么区别,认真来看,第一次执行checkscrop()返回的是一个计算好的结果,而第二段代码中执行checkscrop()返回的是一个函数对象,然后在调用这个函数对象,这就是一个简单的闭包,同时通过第二段代码可以看出,变量的作用域是通过函数创建时候被定义的,而不是在函数被调用是才定义。
如果你理解了以上作用域的规则,你就很容易理解闭包了。
闭包实际上就是为了方便外部访问函数内部的变量实现的,通俗的形式就是一个函数A嵌套另一个函数B并返回函数B,函数B引用了函数A中定义的变量,代码如下:
function A(){
var a="闭包";
return function B(){
return a;
}
}
var result=A();
result();
以上就是一个简单的闭包,之所以实现闭包有两个好处,第一个是方便了函数外部可以访问到函数内部的变量,其次,函数内部的变量在函数执行完成之后可以一直保存在内存中不被回收,在某些场景下为我们提供便利。
同时由于闭包产生的变量会被存储在内存中不被回收,消耗内存,在IE中可能会造成内存泄漏,所以不能滥用闭包,在使用闭包的过程中,在函数执行完成之后将不必要的变量设置为null释放内存。
在文章的最后作者顺带提一下js的垃圾回收机制:
我们将作用域描述为一个对象,每次调用函数的时候就会将函数申明的变量存储在这个作用域对象中,函数在return的时候讲这个对象删除,如果函数不存在嵌套的函数,这个对象就会被当做垃圾回收掉,如果嵌套了一个函数,并且将这个函数作为返回值返回,那么这个嵌套函数所使用的变量就不会被删除。