
本文共 3755 字,大约阅读时间需要 12 分钟。
6.静态属性
- 类的实例成员。仅当类被实例化的时候才会被初始化的属性。使用this前缀访问
- 类的静态成员。存在于类本身上面而不是类的实例上。使用类名(Grid)前缀访问,(不管是在类的里面还是外面都是这样访问)
class Grid { static origin = {x: 0, y: 0}; calculateDistanceFromOrigin(point: {x: number; y: number;}) { let xDist = (point.x - Grid.origin.x); let yDist = (point.y - Grid.origin.y); return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale; } constructor (public scale: number) { }}let grid1 = new Grid(1.0); // 1x scalelet grid2 = new Grid(5.0); // 5x scaleconsole.log(grid1.calculateDistanceFromOrigin({x: 10, y: 10}));console.log(grid2.calculateDistanceFromOrigin({x: 10, y: 10}));
7.抽象类
- 用途:抽象类作为其他派生类的基类使用,也就是说一般充当父类
- 特点:1⃣️一般不会直接被实例化。2⃣️抽象类的非抽象方法可以包括成员细节,抽象方法不能包括具体实现并且必须在派生类中实现(所谓成员细节就是方法内部是怎么实现的)3⃣️如何辨别抽象类和抽象方法,在前面加abstract关键字。
abstract class Animal { abstract makeSound(): void; move(): void { console.log('roaming the earch...'); }}
重点说一下抽象类的抽象方法
- 抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。
- 抽象方法的语法与接口方法相似。 两者都是定义方法签名但不包含方法体。
- 抽象方法必须包含
abstract
关键字并且可以包含访问修饰符。
abstract class Department { constructor(public name: string) { } printName(): void { console.log('Department name: ' + this.name); } abstract printMeeting(): void; // 必须在派生类中实现}class AccountingDepartment extends Department { constructor() { super('Accounting and Auditing'); // 在派生类的构造函数中必须调用 super() } printMeeting(): void { console.log('The Accounting Department meets each Monday at 10am.'); } generateReports(): void { console.log('Generating accounting reports...'); }}let department: Department; // 允许创建一个对抽象类型的引用// department = new Department(); // 错误: 不能创建一个抽象类的实例department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值department.printName();department.printMeeting();department.generateReports(); // 错误: 方法在声明的抽象类中不存在,注意此处报错是因为一开始声明let department: Department; 。并不是说抽象类的子类不能有自己的方法
打印结果
8.高级技巧
构造函数
当你在TypeScript里声明了一个类的时候,实际上同时声明了很多东西。 首先就是类的 实例的类型。
class Greeter { greeting: string; constructor(message: string) { this.greeting = message; } greet() { return "Hello, " + this.greeting; }}let greeter: Greeter;greeter = new Greeter("world");console.log(greeter.greet());
这里,我们写了 let greeter: Greeter
,意思是 Greeter
类的实例的类型是 Greeter
。 这对于用过其它面向对象语言的程序员来讲已经是老习惯了。
我们也创建了一个叫做 构造函数的值。 这个函数会在我们使用 new
创建类实例的时候被调用。 下面我们来看看,上面的代码被编译成JavaScript后是什么样子的:
let Greeter = (function () { function Greeter(message) { this.greeting = message; } Greeter.prototype.greet = function () { return "Hello, " + this.greeting; }; return Greeter;})();let greeter;greeter = new Greeter("world");console.log(greeter.greet());
上面的代码里, let Greeter
将被赋值为构造函数。 当我们调用 new
并执行了这个函数后,便会得到一个类的实例。 这个构造函数也包含了类的所有静态属性。 换个角度说,我们可以认为类具有 实例部分与 静态部分这两个部分。
让我们稍微改写一下这个例子,看看它们之间的区别:
class Greeter { static standardGreeting = "Hello, there"; greeting: string; greet() { if (this.greeting) { return "Hello, " + this.greeting; } else { return Greeter.standardGreeting; } }}let greeter1: Greeter;greeter1 = new Greeter();console.log(greeter1.greet());let greeterMaker: typeof Greeter = Greeter;greeterMaker.standardGreeting = "Hey there!";let greeter2: Greeter = new greeterMaker();console.log(greeter2.greet());
这个例子里, greeter1
与之前看到的一样。 我们实例化 Greeter
类,并使用这个对象。 与我们之前看到的一样。
再之后,我们直接使用类。 我们创建了一个叫做 greeterMaker
的变量。 这个变量保存了这个类或者说保存了类构造函数。 然后我们使用 typeof Greeter
,意思是取Greeter类的类型,而不是实例的类型。 或者更确切的说,"告诉我 Greeter
标识符的类型",也就是构造函数的类型。 这个类型包含了类的所有静态成员和构造函数。 之后,就和前面一样,我们在 greeterMaker
上使用 new
,创建 Greeter
的实例。
把类当做接口使用
如上一节里所讲的,类定义会创建两个东西:类的实例类型和一个构造函数。 因为类可以创建出类型,所以你能够在允许使用接口的地方使用类。
class Point { x: number; y: number;}interface Point3d extends Point { z: number;}let point3d: Point3d = {x: 1, y: 2, z: 3};
发表评论
最新留言
关于作者
