简介

JavaScript语言基于函数和原型链继承机制的方式构建可重用的组件。这对于OO方面编程来说显得比较笨拙。在下一代的JavaScript标准ECMAScript 6为我们提供了基于class base的OO设计方式。在TypeScript中我们也允许使用这种方式,TypeScript将编译为目前大多数浏览器能允许的普通Javascript代码,所以我们不用在等待ECMAScript 6的到来了。

我们先看一个关于class-base的实例:

class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
} var greeter = new Greeter("world");

  

这种语法和我们先前在c#,java语言看见的很相似。在这里我们声明了一个Greeter的类,其中包含一个greeting的属性,构造函数,以及greet的方法。

你也许已经注意到了例子中的‘this’关键字,’this‘和java/C#一样代表对象实例的成员访问。

在最后一行我们利用‘new’关键字创建了一个Greeter的对象实例。这将会新建一个对象实例,并调用我们先前定义的构造函数初始化此对象。

继承

在TypeScript中我们可以使用我们常用的OO设计模式。当然对于OO设计最基本的是类型的继承(继承一个存在的类,复用存在的逻辑),下例就是一个关于类继承的例子:

class Animal {
name:string;
constructor(theName: string) { this.name = theName; }
move(meters: number) {
alert(this.name + " moved " + meters + "m.");
}
} class Snake extends Animal {
constructor(name: string) { super(name); }
move() {
alert("Slithering...");
super.move(5);
}
} class Horse extends Animal {
constructor(name: string) { super(name); }
move() {
alert("Galloping...");
super.move(45);
}
} var sam = new Snake("Sammy the Python");
var tom: Animal = new Horse("Tommy the Palomino"); sam.move();
tom.move(34);

  

在这个案例中展示了TypeScript的OO继承方式,它和其他语言很相似。在TypeScript中我们采用‘extends’关键字来表示类的继承关系。在这里你可以看见 ‘Horse’和’Snake’都是继承至’Animal’的子类实现。

在案例中也展示如何去重写父类的方法,在这里’Snake’和’Horse都各自创建了一个‘move’方法来重写父类’Animal’的‘move’方法,并和‘super’关键字来调用父类的方法。

Private/Public访问限制

Public为默认行为

你可能注意到了在上例中我们并没有用‘public’关键字去描述类的成员的访问级别让其可见。在C#这类语言中,我们必须显示的标注public关键字才能使得类的成员可见。但是在TypeScript中public为默认访问级别,而不是想c#一样private默认。

有时我们希望封装隐藏类的内部成员控制类成员的可见性,这个时候我们可以使用‘private’这类关键字来标示成员。如我们希望隐藏‘Animal’的name属性:

class Animal {
private name:string;
constructor(theName: string) { this.name = theName; }
move(meters: number) {
alert(this.name + " moved " + meters + "m.");
}
}
理解private(私有)

TypeScript有一个结构化的类型(或者鸭子类型)系统。在我们比较两个不同类型,我们不关心它们来自哪里,只关心对类型的每个成员的兼容性。一旦所有的成员都是兼容的,那么我们就认为这两个类型也是兼容的。

当类型检查系统比较两个‘private’成员时,将会认为是不同的对象。对于两个类型比较,当一个类型拥有私有成员的时候,那么另外一个类必须包含相同声明的私有变量(同一处声明,多为继承体现)。如下例:

class Animal {
private name:stringParameter properties;
constructor(theName: string) { this.name = theName; }
} class Rhino extends Animal {
constructor() { super("Rhino"); }
} class Employee {
private name:string;
constructor(theName: string) { this.name = theName; }
} var animal = new Animal("Goat");
var rhino = new Rhino();
var employee = new Employee("Bob"); animal = rhino;
animal = employee; //error: Animal and Employee are not compatible

  

在上例中我们有’Animal’和‘Rhino’两个类型,’Rhino’是‘Animal’的一个子类。同时我们也定义了一个 ‘Employee’的类,它和‘Animal’类完全相同。我们分别创建了第三个类的对象,并相互赋值,结果’Animal’和’Rhino’继承关系,所以对于私有字段name在‘Animal’中具有相同的声明 ‘private name: string’,他们是兼容的。但对于’Employee’则各自声明了一个私有name字段,对于私有字段是不相同的,所以我们不能将employee赋值给animal对象,他们是不兼容的类型。

参数属性(Parameter properties)

访问限制关键字public’和’private也可以通过参数属性方式快捷初始化类成员字段,参数属性可以让我们一步创建类成员。下例是上例中我们去掉了‘theName’,利用‘private name: string’声明在构造函数参数上,它会为我们创建一个私有的name成员的同时初始化这个字段。

class Animal {
constructor(private name: string) { }
move(meters: number) {
alert(this.name + " moved " + meters + "m.");
}
}

  

这里我们利用‘private’关键字为类创建了一个私有成员并初始化其值。对于public也类似。

访问器(Accessors)

TypeScript支持利用getters/setters来控制对成员的访问。让我们可以控制类的成员之间的访问方式。

下面演示如何转化普通的类为get/set方式,如下是没有get/set的方式:

class Employee {
fullName: string;
} var employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
alert(employee.fullName);
}

  

在这里我们允许任意的访问内部fullName成员。有时这可能不是我们所期望的。

在下边我们希望将其转化为在修改fullName的时候必须提供一个正确的passcode,使得不能任意修改此类name,如下:

var passcode = "secret passcode";

class Employee {
private _fullName: string; get fullName(): string {
return this._fullName;
} set fullName(newName: string) {
if (passcode && passcode == "secret passcode") {
this._fullName = newName;
}
else {
alert("Error: Unauthorized update of employee!");
}
}
} var employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
alert(employee.fullName);
}

  

这里我们在修改fullName属性的时候验证了passcode值,是否有权限修改。你可以尝试修改passcode的值,使其不匹配,观察下会发生什么问题?

注意:访问器使用我们需要设置编译输出为ECMAScript 5。

静态属性

回到类主题,上面我们所描述都是关于如何创建类的实例成员。我们同样也可以创建类的静态成员,其可见性为类级访问。我们可以使用’static’ 关键字标注类级成员。在下面的例子中表格原点对于所有表格都是通用的,所以我们可以用‘static’来定义类级成员。那么可以采用类名(Grid.)来访问访问该成员,类似于对象成员的’this.‘.

class Grid {
static origin = {x: 0, y: 0};
calculateDistanceFromOrigin(point: {x: number; y: number;}) {
var xDist = (point.x - Grid.origin.x);
var yDist = (point.y - Grid.origin.y);
return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
}
constructor (public scale: number) { }
} var grid1 = new Grid(1.0); // 1x scale
var grid2 = new Grid(5.0); // 5x scale alert(grid1.calculateDistanceFromOrigin({x: 10, y: 10}));
alert(grid2.calculateDistanceFromOrigin({x: 10, y: 10}));

  

高级特性

构造函数

当我们在TypeScript中声明一个类的时候,有时可能会创建多种声明方式。首先类的实例方式:

class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
} var greeter: Greeter;
greeter = new Greeter("world");
alert(greeter.greet());

  

这里“var greeter: Greeter”首先声明一个Greeter类的实例变量。这在很多OO语言中是很自然的方式。

同时也利用new关键字实例化了这个类的实例,并调用构造函数初始化该对象。下面我们可以看看同等的JavaScript将会如何去做:

var Greeter = (function () {
function Greeter(message) {
this.greeting = message;
}
Greeter.prototype.greet = function () {
return "Hello, " + this.greeting;
};
return Greeter;
})(); var greeter;
greeter = new Greeter("world");
alert(greeter.greet());

这里’var Greeter’被赋值构造函数,并利用‘new’调用了这个方法得到类的实例。同样我们的类也可以包含静态变量。我们可以这么认为所有的类都可以拥有实例和静态两种类型的成员。

让我们对上例稍微做一些修改:

class Greeter {
static standardGreeting = "Hello, there";
greeting: string;
greet() {
if (this.greeting) {
return "Hello, " + this.greeting;
}
else {
return Greeter.standardGreeting;
}
}
} var greeter1: Greeter;
greeter1 = new Greeter();
alert(greeter1.greet()); var greeterMaker: typeof Greeter = Greeter;
greeterMaker.standardGreeting = "Hey there!";
var greeter2:Greeter = new greeterMaker();
alert(greeter2.greet());

  

这里‘greeter1’和上例工作很相似。我们初始化了‘Greeter’类,并调用此对象。其结果在上例已经看见。

接着,我们直接使用了类访问。首先我们定义了一个新的‘greeterMaker’的变量,这变量保持了Greeter类的类型信息,这里我们使用的是‘typeof Greeter’,这会返回Greeter自身的类类型信息。这个类型信息中会包含所以的静态成员信息和实例化对象的构造函数信息。然后通过‘new’ greeterMaker来创建一个Greeter的实例对象,在调用其方法greet。

利用interface来使用class

如上所述,类主要声明了类实例类型和构造函数两件事。因为类主要创建类型,所以我们可以在同一地方使用interface来替代它:

class Point {

x: number;
y: number;
} interface Point3d extends Point { z: number;
} var point3d: Point3d = {x: 1, y: 2, z: 3};

  

注意:TypeScript更准确说是为了类型检查的类型推断。

TypeScript - Classes的更多相关文章

  1. [TypeScript] Create a fluent API using TypeScript classes

    You can create an easy to chain API using TypeScript classes. Learn about the thisreturn type annota ...

  2. Typescript & classes & public shorthand

    classes & public shorthand Also of note, the use of public on arguments to the constructor is a ...

  3. [TypeScript] Sharing Class Behavior with Inheritance in TypeScript

    Typescript classes make inheritance much easier to write and understand. In this lesson we look into ...

  4. [TypeScript] Creating a Class in TypeScript

    Typescript classes make traditional object oriented programming easier to read and write. In this le ...

  5. vscode主题开发

    vscode主题开发教程 https://blog.csdn.net/Suwanqing_su/article/details/105945290 个人配置结果 主题代码 到Vscode放插件的目录中 ...

  6. Inner Classes with TypeScript

    原文:https://blog.oio.de/2014/03/21/inner-classes-typescript/ b.ts class Foo { sex:string; say(){ new ...

  7. Why does Typescript use the keyword “export” to make classes and interfaces public?

    原文: https://stackoverflow.com/questions/15760462/why-does-typescript-use-the-keyword-export-to-make- ...

  8. TypeScript:类(Classes)

    返回TypeScript手册总目录 传统的Javascript关注的是函数(function)和基于原型(prototype-based)的继承作为构建可重复使用组件的基本方式,但是与更舒服地使用面向 ...

  9. 转载:《TypeScript 中文入门教程》 4、类

    版权 文章转载自:https://github.com/zhongsp 建议您直接跳转到上面的网址查看最新版本. 介绍 传统的JavaScript程序使用函数和基于原型的继承来创建可重用的组件,但这对 ...

随机推荐

  1. NI Labview 将图形化系统设计用于肿瘤治疗

    NI Labview 将图形化系统设计用于肿瘤治疗 - Jeff Stevens, Sanarus 挑战:在严格的规则条例范围内保持设计过程的情况下,为通过FDA认证的等级II医疗设备进行设计.原型并 ...

  2. js为空的几种情况

    1.null,对象不存在 var ii= document.getElementById("id"); alert(ii); 当前页面不存在id对象 2. undefined  v ...

  3. 《Linux多线程服务端编程:使用muduo C++网络库》上市半年重印两次,总印数达到了9000册

    <Linux多线程服务端编程:使用muduo C++网络库>这本书自今年一月上市以来,半年之内已经重印两次(加上首印,一共是三次印刷),总印数达到了9000册,这在技术书里已经算是相当不错 ...

  4. mysql三种注释方法

    SELECT * from test;#test表select * from user;-- 用户表select * from tb_test_paper;/*试卷表*/

  5. js处理匿名函数

    首先js 有DOM0 和DOM2级事件 DOM 0级事件处理一般是直接把一个函数分配给一个事件处理程序,既可以在元素中直接分配一个事件处理程序 一个元素可以绑定多个事件 DOM0: <div i ...

  6. php二维数组按照键值排序的方法

    //按照传入数组中的num倒序 public function numdesc($array,$key="num",$order="desc"){ $arr_n ...

  7. 编译nginx时,编译参数注意点

    --prefix=/usr/local/nginx-1.3.1    有利于统一放置nginx的所有文件,方便管理,强烈建议设置 --with-http_stub_status_module    支 ...

  8. [转]c++中vector的使用

    C++中的vector使用范例 一.概述 vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库.vector是一个容器,它能够存放各种类型的对象,简 ...

  9. Windows 安装 openssl

    http://slproweb.com/products/Win32OpenSSL.html File Type Description Win32 OpenSSL v1.1.0b Light 3MB ...

  10. Python成长笔记 - 基础篇 (九)

    创建一个socketserver 至少分以下几步: First, you must create a request handler class by subclassing the BaseRequ ...