|
原文地址是http://flex.sys-con.com/node/309329
第一次尝试翻译了一篇老外的文章,够呛的,英语水平着实有待提高。。。 某些地方大家仁者人仁了,呵呵。 文章是讲As闭包的。 最近对这个东西感兴趣,算是一个比较有意思的语言特性。
翻译如下:
//==========================================================================
闭包是动态语言的基础。实现类似面向对象的特征或搭建框架,它们具有重要的作用。但是,对闭包一个普通的定义并不能帮助我们理解它。让我们通过一些例子来进行。首先,我会举例说明闭包是什么样的,然后介绍它的使用规则。
首先假设存在这样一个匿名函数,它访问函数外的变量
- <?xml version="1.0" encoding="utf-8"?>
- <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="doInit(event)">
- <mx:Script >
- <![CDATA[
- import mx.controls.Alert;
- private var greeting: String = "Hello";
- private function doInit(evt: Event): void {
- btn.addEventListener(MouseEvent.CLICK, function(evt: Event): void {
- Alert.show(greeting + "," + txt.text);
- });
- }
- ]]>
- </mx:Script>
- <mx:Button id="btn" label="closure" />
- <mx:TextInput id="txt" />
- </mx:Application>
复制代码
编译运行上面的代码 以下是关于闭包的描述,非常简单,分为3个部分
1. 闭包是被定义在类或者上下文中的方法,并且一段时间后被传递到另一个对象中执行
2. 闭包调用发生在运行时(可以在程序运行过程中被多次调用)。它是存储所有将被使用的上下文变量(以上实例中的"greeting")的堆栈帧的位子。一般来说,它是描述主程序方法中的变量和当前运行时的类实例。
3. 最后,闭包的执行可以发生在任何时候,并且在被调用时带有参数。通常情况下调用者会把信息包含在一个"Event"对象中传递进来
看起来你可以使用闭包给参数来个"快照"。不幸的是,对于某些动态语言它是可以的,但是作为ECMA标准下的ActionScriot和 JavaScript除外。接下来通过一些例子来解释为什么这样。首先,我们要明确ActionScript闭包是运行时的,而不是动态解释的。我们先调换一下闭包和greetings定义的顺序。
- <?xml version="1.0" encoding="utf-8"?>
- <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="doInit(event)">
- <mx:Script >
- <![CDATA[
- import mx.controls.Alert;
-
-
- private var myClose: Function = function(evt: Event): void {
- Alert.show(greeting + "," + txt.text);
- };
- private function doInit(evt: Event): void {
- btn.addEventListener(MouseEvent.CLICK, myClose);
- }
-
- private var greeting: String = "Hello";
- ]]>
- </mx:Script>
- <mx:Button id="btn" label="closure" />
- <mx:TextInput id="txt" />
- </mx:Application>
复制代码
它依然正常,尽管"greeting"在闭包被定义的时候为undefined--以上证明了闭包仅仅使用的是引用。不像java,一个对象的域是一个封闭函数或类的堆栈帧内容。以下是一个例子,在java中是编译不通过的,但是在As3中却是非常合理:
- private function aaa(): void {
- {var a = 1;} //在java中a在括号外面是不可见的
- Alert.show(a);
- }
复制代码
Flash 是个堆栈机器,在一个封闭的函数当中,一个闭包是一个堆栈变量。这种堆栈帧的方式极大的简化了基于堆栈的闭包和代码优化的实现,尽管在编码的时候它需要一些判断。另一点是,在这里我们不需要对象值,仅仅是引用。让我们在greeting被调用前,将它设置成某个值。
<mx:Button label="closure" click="greeting='good morning'"/>
正如你所看到的,提示框上显示的是一个新的值。"闭包"不会使用greeting在被定义时的值。
闭包是ActionScript中的一等公民。在你的类中,所有方法都是闭包。这就是为什么方法能知道类中所有的实例变量。所有类本质上都是一个大闭包。你可以写一个包含闭包的函数来
像类一样的实现需求。
当你使用异步操作或者向另外一个对象传递事件时,使用闭包是不可避免的。flex与服务器比较重要的交互动作,或者获取用户的输入,他们基本上都是异步的。使用闭包你可以获得类实例的引用,在类实例中的函数完成对外部对象的事件处理。在大部分情况下,这样足以处理异步方法的结果。通过this来引用定义了方法的上下文,极大的简化了编码,因为对于开发人员显得更加自然。
早在flex2之前,flex1.5的时候,开发人员需要为闭包设定好上下文。改变闭包上下文的能力,给实现真正的动态提供了很大的灵活性。
接下来的代码例子描述了在任意对象上的一个闭包可以提供一个用户上下文对象: - public class Closure {
- public function Closure()
- {
- }
-
- public static function create(context: Object, func: Function,...pms): Function {
- var f: Function = function(): * {
- var target: * = arguments.callee.target;
- var func: * = arguments.callee.func;
- var params: * = arguments.callee.params;
- var len: Number = arguments.length;
- var args: Array = new Array(len);
- for(var i: Number = 0; i < len; i++)
- args[i] = arguments[i];
- args["push"].apply(args, params);
- return func.apply(target,args);
- };
- var _f: Object = f;
- _f.target = context;
- _f.func = func;
- _f.params = pms;
- return f;
- }
- }
复制代码
以下代码解释如何调用这个闭包 - <?xml version="1.0" encoding="utf-8"?>
- <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="onCreationComplete(event)">
- <mx:Script >
- <![CDATA[
- import closure_test.Closure;
- import mx.controls.Alert;
- private var myClosure: Function;
-
- private function onCreationComplete(evt: Event): void {
- myClosure = Closure.create({greeting: "Good evening"}, function(name: String): void {
- Alert.show(this.greeting + "," + name);
- },"world");
- var greeting: String;
- greeting = "Hello";
- }
-
- ]]>
- </mx:Script>
- <mx:Button id="btn" label="closure" click="myClosure()"/>
- <mx:TextInput id="txt" />
- </mx:Application>
复制代码
提示显示"Good evening, world" 因为方法调用时使用了不同的上下文。这个方法一般被叫做"委托",被事务框架用于集中处理特定的事件。
上面的例子阐述了上下文,方法和闭包之间的关系。使用这个技术,你可以实现动态继承,多态性和其他面向对象概念
//=====================================Over==================================
|