TypeScript类实践

TypeScript是JavaScript针对可伸缩应用的一个开发方案;它还是强类型、面向对象、编译的编程语言;它是JavaScript的超集;它始于JavaScript也终于JavaScript;总之,它让你以期望的方式编写JavaScript代码。

开始吧,先创建一个Point类:

// ts01.ts
class Point { private x:number; private y:number; public constructor(x:number, y:number) {
this.x = x; this.y = y; } public setPoint(x:number, y:number) { this.x = x; this.y = y; } public getPoint():number[] { return [this.x, this.y]; } }

上面的代码很熟悉吧,完成Point类后,添加下面几行代码测试一下:

var p = new Point(0, 0);
console.log(p);
p.setPoint(5, 5);
console.log(p.getPoint());

测试上面的代码非常简单,就是把TypeScript编译成JavaScript,键入下面命令:

$ tsc ts01

注意,编译ts01.ts并不需要文件扩展名,当然写上扩展名也是可以的。完成编译后可以看到ts01.js,缺省选项时生成的js文件是ES5版本的:

var Point = /** @class */ (function () {
    function Point(x, y) {
        this.x = x;
        this.y = y;
    }
    Point.prototype.setPoint = function (x, y) {
        this.x = x;
        this.y = y;
    };
    Point.prototype.getPoint = function () {
        return [this.x, this.y];
    };
    return Point;
}());

当然,也可以通过选项生成指定的js版本:

$ tsc -t es2016 ts01

再次打开同名js文件可以看到以下ES6的版本:

class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    setPoint(x, y) {
        this.x = x;
        this.y = y;
    }
    getPoint() {
        return [this.x, this.y];
    }
}

上面的例子演示了TypeScript的面向对象、强类型、始终JavaScript的特点。既然是TypeScript Classes Practice就继续玩一下吧,增加一个类Line到ts01.ts:

class Line {
    private p1:Point;
    private p2:Point;

    public constructor(p1:Point, p2:Point) {
        this.p1 = p1;
        this.p2 = p2;
    }

    public setLine(p1:Point, p2:Point) {
        this.p1 = p1;
        this.p2 = p2;
    }

    public getLine():Point[] {
        return [this.p1, this.p2];
    }

    public getSlope():number {
        var x1:number, y1:number, x2:number, y2:number;

        [x1, y1] = this.p1.getPoint();
        [x2, y2] = this.p2.getPoint();

        if (x2 - x1 !== 0) {
            return ((y2 - y1) / (x2 - x1));
        }
        else if (y2 - y1 >= 0) {
            return Number.POSITIVE_INFINITY;
        }
        else {
            return Number.NEGATIVE_INFINITY;
        }
    }

    public getLength():number {
        var x1:number, y1:number, x2:number, y2:number;

        [x1, y1] = this.p1.getPoint();
        [x2, y2] = this.p2.getPoint();
        
        return Math.sqrt(Math.pow((y2 - y1), 2) + Math.pow((x2 - x1), 2));
    }
}

在增加一个Triangle类到ts01.ts:

class Triangle {
    private p1:Point;
    private p2:Point;
    private p3:Point;

    public constructor(p1:Point, p2:Point, p3:Point) {
        this.p1 = p1;
        this.p2 = p2;
        this.p3 = p3;
    }

    public setTriangle(p1:Point, p2:Point, p3:Point) {
        this.p1 = p1;
        this.p2 = p2;
        this.p3 = p3;
    }

    public getTriangle():Point[] {
        return [this.p1, this.p2, this.p3];
    }

    public getSides():number[] {
        return [
            (new Line(this.p1, this.p2)).getLength(),
            (new Line(this.p1, this.p3)).getLength(),
            (new Line(this.p2, this.p3)).getLength()
        ];
    }

    public getArea():number {
        var sides:number[] = this.getSides();
        var ts:number = 0;

        sides.forEach((s) => {
            ts += s;
        })

        ts /= 2;

        return Math.sqrt(ts * (ts - sides[0]) * (ts - sides[1]) * (ts - sides[2]));
    }

    public getHeights():number[] {
        var sides:number[] = this.getSides();
        var area:number = this.getArea();
        var heights:number[] = [];

        sides.forEach((s) => {
            heights.push(area * 2 / s);
        });

        return heights;
    }

    public getRadAngles():number[] {
        var sides:number[] = this.getSides();
        var heights:number[] = this.getHeights();
        var angles:number[] = [];

        angles.push(Math.asin(heights[0] / sides[1]));
        angles.push(Math.asin(heights[2] / sides[0]));
        angles.push(Math.asin(heights[1] / sides[2]));

        return angles;
    }

    public getDegAngles():number[] {
        var rangles:number[] = this.getRadAngles();
        var gangles:number[] = [];

        rangles.forEach((s) => {
            gangles.push(s / Math.PI * 180);
        });

        return gangles;
    }
}

下面是测试代码,同样加到ts01.ts的末尾处:

var p1 = new Point(0, 0), p2 = new Point(3, 5), p3 = new Point(3, 0);
var l = new Line(p1, p2);
var t = new Triangle(p1, p2, p3);

console.log(p1);
console.log(p2);
console.log(p3);

console.log(l);
console.log(l.getSlope());
console.log(l.getLength());

console.log(t);
console.log(t.getSides());
console.log(t.getArea());
console.log(t.getHeights());
console.log(t.getRadAngles());
console.log(t.getDegAngles());

编译完成后键入node ts01运行代码可以看到下面类似结果:

Point { x: 0, y: 0 }
Point { x: 3, y: 5 }
Point { x: 3, y: 0 }
Line { p1: Point { x: 0, y: 0 }, p2: Point { x: 3, y: 5 } }
1.6666666666666667
5.830951894845301
Triangle {
  p1: Point { x: 0, y: 0 },
  p2: Point { x: 3, y: 5 },
  p3: Point { x: 3, y: 0 } }
[ 5.830951894845301, 3, 5 ]
7.5
[ 2.5724787771376323, 5, 3 ]
[ 1.0303768265243123, 0.540419500270584, 1.5707963267948966 ]
[ 59.03624346792647, 30.963756532073518, 90 ]

下面新类Circle继承了Point:

class Circle extends Point {
    private radius:number;

    public constructor(x:number, y:number, radius:number) {
        super(x, y);
        this.radius = radius;
    }

    public setCircle(x:number, y:number, radius:number) {
        super.setPoint(x, y);
        this.radius = radius;
    }

    public getCircle():number[] {
        var x1:number, y1:number;
        [x1, y1] = super.getPoint();
        return [x1, y1, this.radius];
    }

    public getPerimeter():number {
        return (this.radius * 2 * Math.PI);
    }

    public getArea():number {
        return (Math.pow(this.radius, 2) * Math.PI);
    }
}

以上是TypeScript关于类的一些基本特性,涉及了类继承及ES6的解构,当使用"-t es2016"选项把TypeScript编译为ES6的版本时,可以看到js源码基本上没有什么瑕疵,非常棒;不过对于ES5这些 ES6的特性是怎么处理的呢?回顾一下TypeScript源码Line类中的getLength方法,其中用到了解构,在ES5中这段代码如下:

Line.prototype.getLength = function () {
    var x1, y1, x2, y2;
    _a = this.p1.getPoint(), x1 = _a[0], y1 = _a[1];
    _b = this.p2.getPoint(), x2 = _b[0], y2 = _b[1];
    return Math.sqrt(Math.pow((y2 - y1), 2) + Math.pow((x2 - x1), 2));
    var _a, _b;
};

上述代码的执行不会有任何问题,但可以发现在return之后多了个变量声明的语句,无论是何意图都可以把它挪到方法的前部,如下:

Line.prototype.getLength = function () {
    var x1, y1, x2, y2;
    var _a, _b;
    _a = this.p1.getPoint(), x1 = _a[0], y1 = _a[1];
    _b = this.p2.getPoint(), x2 = _b[0], y2 = _b[1];
    return Math.sqrt(Math.pow((y2 - y1), 2) + Math.pow((x2 - x1), 2));
};

目前最新的TypeScript编译器版本是2.5.3,针对解构的编译这是一个小问题。

posted @ 2017-10-18 16:38  Jinzd  阅读(165)  评论(0)    收藏  举报