什么是闭包
在 JavaScript 和 Python 等语言里,函数可以像数值一样使用,比如给变量赋值、作为参数传递给其他函数,作为函数返回值等等。比如下面这一段代码:
var a = 0;
var fun1 = function(){
var b = 0; // 函数内的局部变量
var inner = function(){ // 内部的一个函数
a = a+1;
b = b+1;
return b; // 返回内部的成员
}
return inner; // 返回一个函数
}
console.log("outside: a=%d", a);
var fun2 = fun1(); // 生成闭包
for (var i = 0; i< 2; i++){
console.log("fun2: b=%d a=%d",fun2(), a); //通过fun2()来访问b
}
var fun3 = fun1(); // 生成第二个闭包
for (var i = 0; i< 2; i++){
console.log("fun3: b=%d a=%d",fun3(), a); // b等于1,重新开始
}
outside: a=0
fun2: b=1 a=1
fun2: b=2 a=2
fun3: b=1 a=3
fun3: b=2 a=4
- 内层函数 inner 能够访问其可以看得见的变量,包括自己的本地变量、外层函数变量b和全局变量a。
- 声明 inner 函数时,就告诉它可以访问b,之后就算 inner 当函数赋值给了其他变量,也不影响它正常的访问。
我们可以认为,闭包是为了让函数能够在这种情况下继续运行所提供的一种方案。
静态作用域 vs 动态作用域
int i = 1;
void foo(){
println(i); // 访问全局变量
}
foo(); // 访问全局变量
void bar(){
int i = 2;
foo(); // 在这里调用foo(),访问的仍然是全局变量
}
静态作用域 / 词法作用域(Lexcical Scope):编译时函数能够访问哪些变量,就跟这些变量进行绑定了,使用静态变量 i = 1;
动态作用域(Runtime Scope):变量的引用跟声明不是在编译时就绑定死的,比如使用的是 int i = 2;