(AS3)在循环语句for、for each、while等语句中使用闭包需要注意的地方
2012-04-28 10:20
531 查看
遇到一个很有意思的BUG,是关于闭包的使用,大概简化后类似于以下代码:
var arr:Array = [];
for (var i:int = 0; i < 2; i++)
{
arr[i] = function():void
{
trace(i);
}
}
for each (var f:Function in arr)
{
f();
}
猜一下上面代码的输出是什么?答案是:2 2
而事实上我期望的结果是:0 1
可为什么结果和我的期望相差这么大呢?
再看一段Lua代码:
arr = {}
for i=0,1 do
arr[#arr+1] = function()
print(i)
end
end
for _,v in ipairs(arr) do
v()
end
再猜一下,上面的答案?
这回的结果正好是我期望的结果,输出是:0 1
上面两段代码应该差不多是等价的,不过AS3中却并没有输出我期望的结果。
从我个人的期望上来说,我所理解的闭包,应该能在我定义function的时候就把所有的上下文保存好,这样也就能在调用的时候正确的取到upvalue,也就能正常的输出了。
对于这点,Lua的运行结果正是我需要的,可无奈的是我的主要开发语言是AS3,似乎AS3的闭包实现机制有些问题?循环语句中的 i 是一个引用,而再次调用 f 的时候,拿到的 i 还是原来的那个。
查了查资料,事实上早有人遇到过我类似的问题,传送门:http://stackoverflow.com/questions/422784/how-to-fix-closure-problem-in-actionscript-3-as3
所以,也就有了以下的解决方法,看代码:
var arr:Array = [];
for (var i:int = 0; i < 2; i++)
{
arr.push(test(i));
function test(i:int):Function
{
return function():void
{
trace(i);
}
}
}
for each (var f:Function in arr)
{
f();
}
这里做了件很巧妙的事情, test 方法返回了一个 function ,test 方法本身接受一个参数,而函数在传参过程中,类似 i:int 这样的基础类型数据是传值的,也就是说会拷贝一份 i 的复本出来,相同的数据类型还有其他的包括 Boolean 、Number 、String 、uint。
所以当调用 test 方法的时候实际上是保存了一个 i 的复本。然后 arr 再把 test 返回的方法塞进去,因此在调用 arr 中的方法的时候实际上调用的是 test 返回的那个匿名方法。
因此上面的输出就是我们期望的输出:0 1
这算不算一个BUG呢,不完整的闭包吗?
var arr:Array = [];
for (var i:int = 0; i < 2; i++)
{
arr[i] = function():void
{
trace(i);
}
}
for each (var f:Function in arr)
{
f();
}
猜一下上面代码的输出是什么?答案是:2 2
而事实上我期望的结果是:0 1
可为什么结果和我的期望相差这么大呢?
再看一段Lua代码:
arr = {}
for i=0,1 do
arr[#arr+1] = function()
print(i)
end
end
for _,v in ipairs(arr) do
v()
end
再猜一下,上面的答案?
这回的结果正好是我期望的结果,输出是:0 1
上面两段代码应该差不多是等价的,不过AS3中却并没有输出我期望的结果。
从我个人的期望上来说,我所理解的闭包,应该能在我定义function的时候就把所有的上下文保存好,这样也就能在调用的时候正确的取到upvalue,也就能正常的输出了。
对于这点,Lua的运行结果正是我需要的,可无奈的是我的主要开发语言是AS3,似乎AS3的闭包实现机制有些问题?循环语句中的 i 是一个引用,而再次调用 f 的时候,拿到的 i 还是原来的那个。
查了查资料,事实上早有人遇到过我类似的问题,传送门:http://stackoverflow.com/questions/422784/how-to-fix-closure-problem-in-actionscript-3-as3
所以,也就有了以下的解决方法,看代码:
var arr:Array = [];
for (var i:int = 0; i < 2; i++)
{
arr.push(test(i));
function test(i:int):Function
{
return function():void
{
trace(i);
}
}
}
for each (var f:Function in arr)
{
f();
}
这里做了件很巧妙的事情, test 方法返回了一个 function ,test 方法本身接受一个参数,而函数在传参过程中,类似 i:int 这样的基础类型数据是传值的,也就是说会拷贝一份 i 的复本出来,相同的数据类型还有其他的包括 Boolean 、Number 、String 、uint。
所以当调用 test 方法的时候实际上是保存了一个 i 的复本。然后 arr 再把 test 返回的方法塞进去,因此在调用 arr 中的方法的时候实际上调用的是 test 返回的那个匿名方法。
因此上面的输出就是我们期望的输出:0 1
这算不算一个BUG呢,不完整的闭包吗?
相关文章推荐
- Go中使用for..range语句时需要注意的地方
- 求1+2+…+n,要求不能使用乘除法、for、while、if、else、s witch、case 等关键字以及条件判断语句(A?B:C)和不用循环/goto/递归输出1~100的10种写法
- access中使用SQL语句需要注意的几个地方
- Objective-C学习笔记(十)——循环语句for和do-while的使用
- js---javaScript(循环语句的使用实例)for while do....while(转移语句): break, continue , return
- access中使用SQL语句需要注意的几个地方
- C#--第2周实验--任务四--编写一个控制台应用--分别使用for,while,do-while循环语句计算 n!
- C#中循环语句:while、for、foreach的使用
- 在mybatis中使用多语句执行需要注意的地方
- PL/SQL语句学习之使用while、loop和for三种循环打印数字的1-10
- c++中的结构化语句 判断语句if 分支语句switch 循环语句 while 和 do while 循环语句for的使用
- VUE2 中 v-for,v-on:click 使用需要注意的地方
- 使用for、while 以及repeat-break实现循环语句
- C语言中循环结构语句 for循环及while,do--while 的使用
- 循环语句的使用——while、do_while、for
- 第二周 任务四 分别使用for,while,do-while循环语句计算 n!
- SHELLcase流程控制和for、while循环语句的使用
- AS3 TextEvent使用时需要注意的地方
- 选择 | 循环 | 语句(if,if……else,switch,while,for)的理解和使用
- 循环与递归--不使用if,while,for,do—while语句来输出所有比已知数N小的自然数