在维基百科上对与闭包的理解是这样的:闭包是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即便已经离开了创造它的环境也不例外。
在JavaScript中,咱们能够这样理解:当函数能够记住并访问所在的词法做用域,即便函数是在当前的函数词法做用域以外执行,这是就产生了闭包javascript
要想理解闭包,首先要知道做用域的概念java
做用域是根据名称查找变量的一套规则,例如闭包
var a = 2
这个声明,会有两个过程,首先编译时,编译器会在当前做用于声明这个变量(若是以前没有声明过的话),其次,引擎会询问当前做用域是否有a这个变量,若是是,则将2赋值给它,若是否,则继续查找这个变量函数
当一个块或者一个函数嵌套在另外一个块或函数里,就产生了做用域嵌套,在当前做用域查找不到变量时会在向上查找,就比如,一个高楼,我要去一个朋友家里,我要在第一层查找朋友家,可是若是没找到,就要去上一层,若是到达了顶层还没找到,咱们就不会在继续查找了。code
咱们以前说过当函数能够记住并访问所在的词法做用域,即便函数是在当前的函数词法做用域以外执行,这是就产生了闭包
看一下下面的代码对象
function foo(){ var a = 'dog'; function bar(){ console.log(a) } bar(); } foo();
咱们能够看到bar函数可以访问在foo函数里定义的a,但这只是闭包的一部分,bar对a的引用,能够看做是做用域的查找规则。则这些规则也是闭包的一部分。
那什么是真正的闭包的?ip
function foo(){ var a = 'dog'; function bar(){ console.log(a); } return bar } var baz = foo(); baz(); //dog
咱们能够看到,bar函数能够访问foo函数的做用域内部,以后咱们把bar自己看成返回值赋值给baz,经过baz的调用来执行bar函数,实际上就是根据不一样的标识符来调用bar函数,达到在当前词法做用域外执行的目的。
固然不管以何种方式对函数类型的值进行传递,让函数在别处也能被调用到作用域
function foo(){ var name = 'dog'; function bar(){ console.log(name); } baz(bar); } function baz(fn){ fn(); }
咱们能够经过来实现模块编译器
function module(){ var name = 'dog'; var age = 13; function SayName(){ console.log(name); } function SayAge(){ console.log(age); } return { SayName: SayName SayAge: SayAge } } var foo = module(); foo.SayName(); // dog foo.SayAge(); // 13
这个模式在javascript中被称为模块
咱们来分析一下这个代码,module函数返回一个对象,这个返回的对象保存了对内部函数而不是内部变量的引用,咱们保持对数据的隐私且私有的状态,能够将这个对象类型的返回值看做是一个公共API。这个返回的对象类型咱们赋值给了foo,以后经过foo来调用这个API的属性访问。SayAge()和SayName()函数具备涵盖模块实例内部做用域的闭包,当经过返回一个含有属性引用的对象方式来说函数传递到词法做用域外部时,就创造了观察闭包的条件io