# 闭包

请参考：

- [定义函数](definitions.html)
- [局部变量](../variables-and-constants.html#var)

## 闭包(Closure)

### 创建闭包

在了解闭包以前，我们首先要了解几个基础知识：

1. 局部变量作用域总是向内向下有效，函数内部的局部变量仅在函数内部有效。

2. aardio 根据标志符查找"命名对象"的顺序依次为：  

    1. 当前语句块局部变量。
    2. 在上层语句块就近搜索局部变量，搜索时可以跨域所有外层函数。 
    3. 搜索当前命名空间( self )的成员变量。

    要点：
    - 在一个函数内部可以使用外层函数定义的局部变量，除非在函数内部定义了同名的局部变量。 
    - aardio 代码文件本身也是一个匿名函数，所以我们定义函数时一般都会是在另一个外层函数的内部定义函数。
    - 如果当前命名空间不是全局命名空间，aardio 默认不会到全局表查找命名对象，除非标识符指向一个全局有效的命名对象（全局常量、保留常量、保留函数名）或使用 `..` 操作符明确指定仅在全局表中查找命名对象 。

请看下面的代码：

```aardio
//此函数用于创建并返回另一个函数
var createFuncion = function(){
	
	var counter  = 0;
	
	return function(){
		//使用了外层函数的局部变量
		counter++;
		return counter; 
	} 
}

//创建函数
var myFunc = createFuncion();

//调用新的函数
var next = myFunc(); 
```

参考以上代码：当使用一个函数（ createFuncion ）创建并返回一个内部函数（ myFunc ）以后，内部函数（ myFunc ）使用的外层函数的局部变量（ counter ）并不会销毁，这些外层函数的局部变量（ counter ）仍然保存在一个独立的闭包中。

闭包要点:

- 每次调用一个外部函数，aardio 总是会为该函数内部的函数创建一个新的闭包实例。闭包为内部函数提供了一个初始化私有数据的机会。
- 闭包限制在闭包内定义的局部变量仅在闭包内部有效，闭包有保护私有数据的作用。
- 闭包保存一个函数需要引用的外部的局部变量，闭包有保护函数运行环境的作用。

> 注意：在函数内部的函数，即使不是局部函数（一般情况下这样做不是一个好主意），仍然可以使用上层函数的闭包内的数据，直这些函数或闭部变量不再存在外部引用而被回收。

### 闭包的生命周期   
  
在外部函数调用结束后，为内部函数创建的闭包仍然可以存在，直到闭包内的所有内部函数都销毁，并且不再有任何外部对象引用到闭包内的数据，闭包才会被垃圾回收器自动回收。

其实闭包与类（ class ）是以不同的方式解决了类似的问题。函数创建闭包的过程类似于使用类（ class ）创建对象的过程，区别在于创建闭包的是函数、闭包返回的是函数对象，类返回的是 table 对象。类创建的 table 对象一般都会有公开的成员，而闭包则完全是黑盒机制主要用于保存受私有数据。  

## 迭代器

迭代器是闭包的主要应用之一，请参考：[泛型 for 与迭代器](../statements/iterator.html)