闭包

1.个人定义

2.闭包是如何产生的

3.不仅仅是词法作用域

1.个人定义

闭包可以看作是javascript函数的一种特性。

2.闭包是如何产生的


从程序语言的角度来看,闭包产生的原因,就是基于词法作用域的作用域链的访问规则。

javascript中作用域只有两种类型,天生的全局环境和函数调用生成的局部环境。

嵌套的调用会产生多个嵌套的环境,就像栈那样。



对于语言的设计者来讲,就有了一个必须解决的问题,那就是:当你在局部作用域里找不到

某一个标识符的时候,是否跨可以作用域寻找。

最简单粗暴的策略是,找不到就报错,不容许跨作用域找查。
```
/* 1.0 */
var a=10;
function fun_1(){
        console.log(a);
}
fun_1();            //如果语言被设计为不容许跨越作用域 那么这段代码报错
```

这种设计比较简(愚)单(蠢),函数无法获得外部的任何信息,如果必要,信息要以参数的形式传入。


第二种策略,容许标识符的解析跨越作用域。

也就是说,这个作用域里找不到这个标识符,那么就到上一个作用域中去找(当然不能去下一个,因

为下一个作用域还没有生成呢)。

几乎所有的编程语言都支持这种策略,但是在这种策略的具体实现上,设计者们产生了分歧,一个新

的问题是: 到底谁才是上一个作用域?。

由于函数调用就像栈的压,出,理所当然的一种策略就是,按调用的顺序来,每一个调用者的作用域都是被

调用者的上一个作用域,就也就是动态作用域。

```
/* 1.1 */
var a=10;
function fun_1(){
        console.log(a);
}
fun_1(); // 输出10
(function(){
var a='xxx';
fun_1();//输出 ‘xxx’
})();
```
这种动态作用域,很依赖于函数调用的位置,不同的位置,函数访问的上一个作用域也不相同。

javascript的设计者明显不喜欢这样的设计,语言的设计者,希望函数的上一个作用域,

在声明或者是定义的那个地方就确定了,就像一个隐藏的bind。

正所谓,javascript函数运行在它们被定义的作用域内,而不是它们被执行的作用域内,这就是

所谓的词法作用域,与函数在那里调用无关。

```
/* 1.2 */
var a='galbol';
function fun_1(){
          console.log(a);
} //全局环境下定义
fun_1(); // 输出'global'    //全局环境下调用
(function(){
var a='xxx';
fun_1();//输出 ‘global’  //嵌套在函数中调用
})();
```
这个例子可以看到,我们在全局作用域中定义了函数fun_1,所以,fun_1的上一个作用域即全局作

用域,不管在那里被调用,都不会被影响。

这样就产生了闭包,当然上述的例子很单调,无法展现闭包的强大之处,看一下这个例子。

```
/* 1.3 */
function fun_1(){
  var x=100;
return function(){
  console.log(x);
  }
}
fun_2=fun_1();
fun_2() //输出100
```
fun_1中定义了一个匿名函数,根据词法作用域,匿名函数的上一个作用域,也就是fun_1调用时生成的

局部作用域,即时fun_1调用完毕,这个作用域也不能被垃圾回收处理,因为返回的这个匿名函数,可能

使用了fun_1局部作用域中的数据,也只有这个匿名函数能够访问到这个局部作用域中的数据,这就是闭

包的强大之处。

3.不仅仅是词法作用域

在javascript中,有两个特殊的例子
1.this this在javascript是个关键字,它的值取决于调用位置,即动态的。

2.Function构造函数生成的函数,也是闭包,不过函数的上一个作用域永远是全局作用域,而不是声明和定义它们的地方。
posted @ 2017-09-26 21:11  split  阅读(179)  评论(0编辑  收藏  举报