IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    从 ActionScript3 到 TypeScript

    Nshen (nshen121@gmail.com)发表于 2014-12-07 01:52:07
    love 0

    以下是我总结的笔记,只涉及语法部分,有错漏请指正。

    如果你只想把现有的AS3代码转换为TypeScript代码的话,请尝试我写的这个在线转换器

    基本类型

    基础类型只有这么几种,与AS3对比

    TypeScript ActionScript3
    number Number
    string String
    boolean(0.8以前为bool) Boolean
    any *
    undefined undefined
    null null

    任意类型:

    ActionScript3 :

    var anyType : * = ...;
    

    TypeScript:

    var anyType : any = ...;
    

    变量修饰符:

    TS类似AS3 但不用写”var” , 没有protected (未来也许会添加),默认为public。

    ActionScript3 :

    private var str: String = "abc";    
    public  var num: Number = 123;     
    var num2 :Number = 456;        
    static var bo: Boolean = true;    
    public var createTime: String;  
    

    TypeScript:

     private str: string = "abc";    // private property
     public  num: number = 123;      // public property
     num2 :number = 456;             // 不写默认也为public
     static bo: boolean = true;         // static
     public createTime: string;      //createTime 类型为string,值为 undefined
    

    变量类型转换:

    ActionScript3 :

    var str:String = "abc";
    var strNum:Number = Number(str);
    var strNum:Number = str as Number;
    

    TypeScript :

     var str : string = "abc";
     var strNum: number =  str; //编译报错 Cannot convert 'string' to 'number'
    

    发现使用any类型会编译通过:

     var str2 :any = "abc"; //any类型
     var strNum2 :number = <number> str2; //通过
     strNum2 += 5; // abc5 
    

    用 instanceof 判断类型

     // instanceof
     function CalculateArea(shape : Shape) : number {
         if (shape instanceof Square) {
         return (shape).x * (shape).y;
     }
     if (shape instanceof Ellipse) {
         return (shape).r1 * (shape).r2 * Math.PI;
     }
     if (shape instanceof Triangle) {
         return 0.5 * (shape).x * (shape).y;
     }
     throw new TypeError("Unsupported type!");
    }
    

    数组

    Typescript数组的写法比AS3漂亮很多

    ActionScript3 :

    var arr:Array = [1,2,3,"a","b","c"]; // 任意类型数组
    var strArray:Vector.<String> = Vector.<String>(["a", "b", "c"]); //固定类型数组
    

    TypeScript :

    var arr: any[] = new Array(); // 任意类型数组
    var strArr: string[] = ["a", "b", "c" ]; //固定类型数组
    

    二维数组

    var array2d: string[][] = [
    ["a", "b", "c"],
    ["x", "y", "z"]
    ];
    
    // or
    
    var array2d: string[][] = new Array();
    array2d.push(["a", "b", "c"]);
    array2d.push(["x", "y", "z"]);
    

    Object Types

    当AS3调用这样一个函数时,会有下面一个问题。

    ActionScript3 :

    function CalculateArea ( rect : Object ):Number
    {
          return rect.width * rect.height;
    }
    

    此时编译器并不知道rect这个Object里到底有没有width和height,只能等到runtime时才会知道。

    TypeScript 引入Object Types解决这一问题,可以指定Object参数的具体内容,相当于让Object参数实现了interface

    function CalculateArea(rect: {width: number; height: number;}): number
    {
        return rect.width * rect.height;
    }
    

    此时如果调用CalculateArea({w:123,h:456}); 编译器不会通过。

    Object Types 还支持”?”表示可选参数

    function CalculateArea(rect: {width:number; height:number; depth?:number;}): number
    {
        if(rect.depth)
        {
            return rect.width * rect.height * rect.depth;
        }
        return rect.width * rect.height;
    }
    
    CalculateArea({w:123,h:456}); //编译器报错
    CalculateArea({width:123,height:456}); // 通过
    CalculateArea({width:123,height:456,depth:789}); // 通过
    

    可以这样声明一个Object

    var example: {
    name: string;
    id: number;
    collection: string[]; 
    } = {
    name: 'Example',
    id: 5,
    collection: ['a', 'b', 'c']
    }
    

    ActionScript3 :

    var fun:Function;   
    var fun2:Function = someFunction;
    

    TypeScript 可以指定Function需要的参数和返回值类型,叫做函数签名,所以变成了这样

    var fun : (str: string) => void;   // fun是输入为string,没有输出的函数
    var fun2 : (num: number) => number = someFnction;  //someFnction函数必须输入输出都为number类型
    

    eg.指定callback函数为string输入,any输出。

    function vote(candidate: string, callback: (result: string) => any) {
    // ...
    } 
    
    vote("BigPig",
        function(result: string) {
            if (result === "BigPig") {
                // ...
            }
        });
    

    TypeScript 这样的语法虽然使Function更清晰了,但也带来麻烦,比如一个简单的输入输出都是string的函数就要写好长不易阅读

    var sayHello: (input: string) => string = function (s: string) {
        return "Hello " + s;
    }
    
    //保存函数的数组也写很长
    var strArray: { (s: string): string; }[] = [sayHello, function aa(str: string) { return str; }];    //两个输入输出都为string的函数
    var strArray: { (s: string) => string; }[]   //这样写会报错,不知道为什么要把 “=>”换成“ :” 不太清楚为什么 -_-b
    

    所以引入了 函数接口

    函数接口

    //定义输入输出都是字符串的函数的接口
    interface IStringFunction {
        (input: string) : string;
    }
    

    上边很长的都可以这么写了

    var sayHello: IStringFunction = function (s: string) {
        return "Hello " + s;
    }
    var strArray: IStringFunction[];
    strArray.push(sayHello);
    

    可选参数加”?”

    //带默认值
    function func (a: number, b?: bool = false): number
     {
        if (b) { return a + b };
        return a;
    }
    
    //不带默认值,要自己判断了
    function func (a: number,b?: bool): number 
    {
      if ( b !== null && b !== undefined )
      {
        if ( b) { return a + b };
       }
       return a;
    }
    

    rest参数 …paramName[:paramType]

    function CountDwarvesTallerThan(minHeight: number, ...dwarves: Dwarf[]) : number 
    {
        var count: number = 0;
        for (var i = 0; i < dwarves.length; i++) {
            if (dwarves[i].height > minHeight) {
                count++;
            }
        }
        return count;
    }
    

    Arrow Function

    关于this作用域的问题,AS1时代经常用到的一个技巧:

    var _this = this

    var messenger = {
        message: "Hello World",
        start: function() {
        var _this = this;
        setTimeout(function() { 
            alert(_this.message); 
            }, 3000);
        }
    };
    messenger.start();
    

    TypeScript把这个技巧封装到语言里了,叫Arrow Function

    语法格式为 ()=>{},例子:

    TypeScript:

    var messenger = {
        message: "Hello World",
        start: function() {
            setTimeout(() => { alert(this.message); }, 3000);
        }
    };
    messenger.start();
    

    编译后的JavaScript跟上边的一样

    var messenger = {
        message: "Hello World",
        start: function () {
            var _this = this;
            setTimeout(function () {
                alert(_this.message);
            }, 3000);
        }
    };
    messenger.start();
    

    网上找到的一个例子,

    //declare var 为环境声明,用来告诉编译器已知的变量类型,例如浏览器定义的一些变量类型
    
    declare var menu: HTMLElement;       
    declare var sideBar: HTMLElement;
    
    class UITester {
        menuTouches: number;
        sidebarTouches: number;
    
        beginMenuTest(): void {
            this.menuTouches = 0;   // Right!!
            menu.onmouseenter = function (e) {
                this.menuTouches++;  // Wrong!! 
            }
        }
    
        beginSidebarTest(): void {
            this.sidebarTouches = 0;  // Right!!
            sideBar.onmousemove = e => {  
                this.sidebarTouches++;  // Still right!!
            }
        }
    }
    

    语法中用了(e)=>{} ,将e传给后边的函数,并且省略了e的括号,会编译成这样:

    var UITester = (function () {
        function UITester() { }
        UITester.prototype.beginMenuTest = function () {
            this.menuTouches = 0;
            menu.onmouseenter = function (e) {
                this.menuTouches++;
            };
        };
        UITester.prototype.beginSidebarTest = function () {
            var _this = this;
            this.sidebarTouches = 0;
            sideBar.onmousemove = function (e) {
                _this.sidebarTouches++;
            };
        };
        return UITester;
    })();
    

    这里有篇教程详细解释了这个语法:

    http://www.codebelt.com/typescript/arrow-function-typescript-tutorial/


    类相关的

    TypeScript中的module相当于ActionScript3中的Package

    TypeScript中构造函数的函数名用constructor ,而不用类名。

    TypeScript:

    module net.nshen { 
        export class Test1
        {
            private str: string = "abc";    // private property
            public  num: number = 123;      //public property
    
            public createTime: string;      //createTime = undefined
    
            constructor() // constructor
            {
                this.createTime = new Date().toUTCString();
            }
    
            static traceDate(): void
            {
                var currentDate: Date = new Date(); 
                console.log(currentDate.toUTCString());
            }
        }
    }
    

    调用Static方法

    net.nshen.Test1.traceDate();
    

    module原理

    module始终是要编译成JS代码的,写一个简单的module看一下原理:

    module M {
        var s = "hello";
        export function f() {
            return s;
         }
    }
    
    M.f();
    M.s;  // Error, s is not exported
    

    编译后的JS代码

    var M;
    (function(M) {
        var s = "hello";
        function f() {
        return s;
        }
        M.f = f;
    })(M||(M={}));
    

    据说这是js界很流行的写法,叫做JavaScript module pattern


    函数重载

    AS3和JS都是不支持函数重载的,TypeScript以一种鸡肋的方式支持着。

    先写一些同名的函数声明,最后在一个同名函数里写出实现(要自己判断参数类型):

    TypeScript:

    function attr(name: string): string;
    function attr(name: string, value: string): Accessor;
    function attr(map: any): Accessor;
    
    function attr(nameOrMap: any, value?: string): any {
        if (nameOrMap && typeof nameOrMap === "object") {
            // handle map case
        }
        else {
            // handle string case
        }
    }
    

    最终会编译成一个JS方法:

    JavaScript:

    function attr(nameOrMap, value) {
        if (nameOrMap && typeof nameOrMap === "object") {
        } else {
        }
    }
    

    2014/12/07 补充 : js判断类型也是个很大的坑,详见 http://tobyho.com/2011/01/28/checking-types-in-javascript/

    TypeScript 允许多个类在同一个文件里,但如果类与类在不同的文件,需要这种写法,相当于AS3 的 import

    /// 
    class ComplexWebSocket extends SimpleWebSocket {
    ...
    }
    

    override方法子类不需要写关键字,直接同名方法即可 ,可调用super.xxx()

    class Base {
    
        public test():number
        {
            return 1;
        }
    
        public test2():number
        {
            return 2;
        }
    }
    
    class Derived extends Base {
    
        public test():number
        {
            return 3;
        }
    
        public test2():number
        {
            return super.test();
        }
    
    }
    
    
    var d:Derived = new Derived();
    console.log(d.test()); // 3
    console.log(d.test2());// 1
    

    Enum

    TypeScript支持enum关键字

    enum Color { Red, Green, Blue }
    console.log(Color.Red); // 0
    var c:number = Color.Green;
    console.log(Color[c])  //Green
    

    生成对应的js

    var Color;
    (function (Color) {
        Color[Color["Red"] = 0] = "Red";
        Color[Color["Green"] = 1] = "Green";
        Color[Color["Blue"] = 2] = "Blue";
    })(Color || (Color = {}));
    console.log(Color.Red);
    var c = Color.Green;
    console.log(Color[c]);//Green
    


沪ICP备19023445号-2号
友情链接