这段代码中,程序员希望foo函数中的变量i被内部循环的函数使用,并且能分别获得他们的索引,而实际上,只能获得该变量最后保留的值,也就是说.闭包中所记录的自由变量,只是对这个变量的一个引用,而非变量的值,当这个变量被改变了,闭包里获取到的变量值,也会被改变.
var result=[];
function foo(){
var i= 0;
for (;i<3;i=i+1){
result[i]=function(){
alert(i)
}
}
};
foo();
result[0](); // 3
result[1](); // 3
result[2](); // 3
这段代码中,程序员希望foo函数中的变量i被内部循环的函数使用,并且能分别获得他们的索引,而实际上,只能获得该变量最后保留的值,也就是说.闭包中所记录的自由变量,只是对这个变量的一个引用,而非变量的值,当这个变量被改变了,闭包里获取到的变量值,也会被改变.
<pre name="code" class="javascript">var result=[];
function foo(){
var i= 0;
for (;i<3;i=i+1){
result[i]=(function(j){
return function(){
alert(j);
};
})(i);
}
};
foo();
result[0](); // 0
result[1](); // 1
result[2](); // 2
让内部函数在循环创建的时候立即执行,并且捕捉当前的索引值,然后记录在自己的一个本地变量里.然后利用返回函数的方法,重写内部函数,让下一次调用的时候,返回本地变量的值
java
</pre><pre code_snippet_id="1560752" snippet_file_name="blog_20160121_4_4788078" name="code" class="java">interface Action
{
void Run();
}
public class ShareClosure {
List<Action> list = new ArrayList<Action>();
int i;
public void Input()
{
for(i=0;i<10;i++)
{
list.add(new Action() {
@Override
public void Run() {
System.out.println(i);
}
});
}
}
public void Output()
{
for(Action a : list){a.Run();}
}
public static void main(String[] args) {
ShareClosure sc = new ShareClosure();
sc.Input();
sc.Output();
}
}
输出:全部为10
<<Java编程思想>>
是一个匿名的代码块,可以接受参数,并返回一个返回值,也可以引用和使用在它
周围的,可见域中定义的变量。-- Groovy ['ɡru:vi]
是一个表达式,它具有自由变量及邦定这些变量的上下文环境。
闭包允许你将一些行为封装,将它像一个对象一样传来递去,而且它依然能够访问
到原来第一次声明时的上下文。
是指拥有多个变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这
些变量也是该表达式的一部分。
闭包是可以包含自由(未绑定)变量的代码块;这些变量不是在这个代码块或者任
何全局上下文中定义的,而是在定义代码块的环境中定义。
在这些定义中都有一些关键字:变量、函数、上下文等,闭包在回调函数、函数式
编程、Lambda表达式中有重要的应用
interface Action
{
void Run();
}
public class ShareClosure {
List<Action> list = new ArrayList<Action>();
public void Input()
{
for(int i=0;i<10;i++)
{
final int copy = i;
list.add(new Action() {
@Override
public void Run() {
System.out.println(copy);
}
});
}
}
public void Output()
{
for(Action a : list){a.Run();}
}
public static void main(String[] args) {
ShareClosure sc = new ShareClosure();
sc.Input();
sc.Output();
}
}
输出: 0-9
这两种代码是作用域不同引起的与堆栈管理有关
这个例子创建一个接口列表List<Action> ,先向列表中创建 i 个匿名内部类new
Action(),然后通过for遍历读出。
因为 i 变量在各个匿名内部类中使用,这里产生了闭包共享,java编译器会强制要求
传入匿名内部类中的变量添加final
关键字,所以这里final int copy = i;需要做一个内存拷贝,否则编译不过。(在c#中
没有强制要求会导致列有被遍历时
始终会取 i 最大值,这是因为延迟执行引起的)