• (转)《AS3 Expert》动态语言的基石:函数闭包


    《AS3 Expert》动态语言的基石:函数闭包


    Admin
    2010年6月19日名人名言:时间,每天得到的都是二十四小时,可是一天的时间给勤勉的人带来智慧和力量,给懒散的人只留下一片悔恨。——鲁迅

     原文:http://sban.biz/216


    闭包(Closure)是函数(或方法)及其执行环境的组合体,它不仅包括函数(或方法)本身,也包括函数(或方法)运行时的上下文词汇环境。闭包是所有动态语言的基石,闭包实现了函数(或方法)可以作为参数传递给函数(或方法)。


     


    1,用一个代码实验例示闭包概念


    在AS3中,共种三种闭包:


    1)函数闭包(Function Closure)


    2)方法闭包(Method Closure)


    3)类闭包(Class Closure)


    public class Closure extends Sprite
    {
    public function Closure()
    {
    super();
    init();
    }

    private var author :String = "sban";
    private var onMouseClick2 :Function = function(e :MouseEvent) : void
    {
    trace("author:" + author, "this:" + this);//author:undefined this:[object global]
    };

    private function init() :void
    {
    var onMouseClick1 : Function = function(e :MouseEvent) : void
    {
    trace("author:" + author, "this:" + this);//author:sban this:[object global]
    };
    this.stage.addEventListener(MouseEvent.CLICK, onMouseClick2);
    }

    private function onMouseClick(e :MouseEvent) :void
    {
    trace("author:" + author, "this:" + this);//author:sban this:[object Closure]
    }

    }


    在上例代码中,分别以onMouseClick,onMouseClick1,onMouseClick2为listener向stage添加click事件监听,trace结果如代码中注释。其中,onMouseClick是方法闭包,onMouseClick1与onMouseClick2是函数闭包。这里有一个问题,为什么在onMouseClick2中author的输出结果是undefined?


    2,三类闭包的区分


    在AS3中,任何一个函数(或方法)调用,至少会有一个this参数,这几乎是所有动态语言一惯的规则,不同的是,有的语言对程序员是可见的,如Python,有的则不可见,如AS3。


    1) 方法闭包


    所有类实例的方法,作为参数传递时,均是方法闭包,隐匿的第一个this参数永远是类实例本身,如上例代码中的onMouseClick便是方法闭包,所以它的this输出为[object Closure]。


    2) 函数闭包


    所有匿名方法(包括局部变量方法,类变量方法,见上),全局方法(包括位于根包下的全局方法,位于子包下的全局方法,见下)均是函数闭包,所有函数闭包的第一个函数如果是null,将被默认替换为Global对象,所以我们看到的输出均是[object global]


    package
    {
    import flash.events.MouseEvent;

    function onMouseClick3(e :MouseEvent) :void
    {
    trace("this:" + this);//this:[object global]
    }
    }

    package sban.as3Expert
    {
    import flash.events.MouseEvent;

    public function onMouseClick4(e :MouseEvent)
    {
    trace("this:" + this);//this:[object global]
    }
    }


    对于位于子包下的函数,可以这样直接使用:


    this.stage.addEventListener(MouseEvent.CLICK, sban.as3Expert.onMouseClick4);

    3)类闭包


    这是三类闭包中最简单的一种,也是最容易区分的一种,可能也是价值最低的一种,貌似根本不应该归为闭包类别。在AS3中,所有显式对象类型转换均是类闭包,如下:


    //if obj is Closure which type anotation is Object
    var obj1 :Closure = Closure(obj);

    Closure在这里不是操作符,也不是别的什么东西,在这里应该把它理解为一个特殊的方法。这个方法第一个参数仍然为this,第二个参数是将被作类型转换的对象,在上例代码中为obj。


    3,改变函数闭包的this参数的一种情况


    在函数闭包中,this参数(null)通常被默默置换为global对象,在某些情况下,程序员可以传递真实的this参数进去,而不是null,从而避免被替换为global对象。


    在Array的forEach, every, map, some, filter这些API中,第一个参数为函数对象,第二个参数为第一个参数的this对象,当程序员指定第二个参数时,便可以在第一个函数内访问this上下文环境的变量,如果不指定,便不能再其内使用this。


    public function ArrayForEachThis()
    {
    super();

    var arr :Array = [1,2,3];
    arr.forEach(
    function (item :int,index :int=-1,arr :Array = null) :void
    {
    trace(item, this.author)
    }
    //,this
    );
    }

    private var author :String = "sban";

    编码规范:在使用Array的forEach, every, map, some, filter这些API时,必须在第二个参数位传递this进去。


    4,为什么在onMouseClick2中author的输出是undefined?


    所有AS3程序员都应当知道,在AS3运行时,有一个作用域链,该作用域链自global始,在运行时变量首先从最近的链点查找,如果未找到,再向上查找,直到找到或到达global链点。


    onMouseClick2函数的运行时作用域链为:


    onMouseClick2闭包->global

    在这个链条内,根本不存在author变量,所以onMouseClick2的输出为undefined。


    而onMouseClick1的作用域链为:


    onMouseClick1->init->Closure->global

    onMouseClick的作用域链为:


    onMouseClick->Closure->global

    这两个作用域链均包括author变量,所以onMouseClick1与onMouseClick均不会输出undefined。


    作用域链的节点包括闭包对象,但不仅包括它。


    sban 2009/5/15 北京。转载请注明作者及出处,非商用。



      • E4X用法简要

      • 命名空间:如何控制未知方法的调用

      • 变量及作用域

      • Traits对象:为什么静态方法不能被继承

      • 像Ruby一样简易行码:使用Prototype扩展原生对象

      • Flash Player的垃圾内存回收机制:能否强制回收?

      • AS3中的一些基本定义,Function与Method的区别

      • AS3中的八种基元类型

      • 在AS3中,如何实现数组及对象的深拷贝?

      • 如何让if语言写的更简洁?(七种布尔转换为假的情况总结)


    作者:sban

    出处:http://sban.biz


    本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。



    时间,每天得到的都是二十四小时,可是一天的时间给勤勉的人带来智慧和力量,给懒散的人只留下一片悔恨。——鲁迅
    来源:http://www.cnblogs.com/sban/archive/2010/05/27/1745357.html
     
     
    补充可有意思的例子:
    package
    {
     import flash.display.Sprite;
     import flash.events.MouseEvent;
     
     public class Main extends Sprite
     {
      public function Main()
      {
       //func1(2);
       //func1(3);
       var b:int=1;
       func1(b);
       b++;
       func1(b);
       
      }
      public function func1(a:int):void
      {
       stage.addEventListener(MouseEvent.CLICK,func2);
        function func2(e:MouseEvent):void
       {
        trace(a);
       }
       return;
       
      }
      
      
      
     }
    }

    在场景上按一下,结果:

    1

    2

    充分说明了运行时保存上下文环境的特性。

  • 相关阅读:
    【转载】面试70问 经典回答
    USB基础知识
    TCPDUMP 使用教程
    linux网络性能测试工具ipref安装与使用
    linux查看主板型号、CPU、显卡、硬盘等信息
    Curl请求慢
    mac与windows共享键盘鼠标(synergy)
    Tomcat 配置文件 server.xml
    jumpserver win终端无法添加
    进程占用情况记录
  • 原文地址:https://www.cnblogs.com/wonderKK/p/2618800.html
Copyright © 2020-2023  润新知