闭包的概念
闭包是函数和声明该函数的词法环境的组合。
这是官方文档,给出的标准的闭包定义。它是什么意思呢?
它说明了两个方面,一方面着重强调了函数,一方面着重强调了词法环境。
有人说,函数套函数,就是闭包!我认为,这是不正确的。
函数套函数,说明了闭包的函数声明,但是忽略了函数的词法环境。
函数的词法环境
function test(){
var a = 1;
function test1(){
console.log(a);
}
test1();
}
这个示例中,我们在test函数中定义了test1函数,对于test1函数而言,var a = 1,就是它的词法环境。我在我的函数内部,可以访问外部的变量。
那这个就是闭包吗?显然不是!因为test函数执行完毕,就释放了所有的空间。
闭包
那到底什么才算是闭包?
把上面的示例稍微改造一下:
function test(){
var a = 1;
return function(){
console.log(a);
}
}
我们在执行test函数的时候,返回了一个function。而这个返回的function可以访问函数内部的变量 a。
一般而言,一个函数在执行完毕,就释放了自身的内存空间,但是这个test函数执行了,你还不能释放它的内存空间,因为它的返回值是一个函数!!这个函数还在使用变量 a 呢!!释放了空间就会出问题!!
所以,这样就形成了一个闭包!执行了test函数,test函数内部的词法环境还没有被释放,同时它的返回值是一个function,可以访问test词法环境中的变量。
闭包有啥用呢
第一、解决循环添加点击事件的索引i 的问题。
for(var i = 0; i < list.length; i++){
list[i].onclick = function(){
console.log(i)
}
}
打印出的东西绝对不是0,1,2,3。。。。
使用闭包就能完美解决这个问题。
第二、模拟私有变量。
在设计模式中,有一种模式,叫做模块模式。
var module = (function(){
var a = 1;
function init(){
console.log(a);
}
return {
init: init
}
})();
其中,a就是module模块的私有变量,很多框架就是基于这样的模式来实现的。比如zepTo.js、underscore.js等等。
第三、闭包在面向对象中的思考
我们在创建对象的时候,由于闭包会影响函数的性能。所以函数一般定义在原型上。
最终形成了面向对象中的实例属性、原型方法的构造方式。