在第二天的学习中,了解了如何使用TypeScript创建一个简单的类。今天,将更深入地探索类的概念,展示如何添加自定义构造函数以及如何控制类外部代码对字段的访问权限。
承认,写一个简单的加法类让感到有些无聊,所以决定写一个更有趣的类。今天,将编写一个名为Point
的类。作为一名专业开发者,喜欢在编写类之前就明确它的功能,所以为这个类设定了以下要求:
x
和一个y
值来表示一个点。IsEmpty
方法,以便可以确定x
和y
值是否不为0,0。Offset
方法来改变x
和y
的值。IsEqual
方法来确定两个点是否相等(具有相同的坐标)。ToString
方法,它会告诉使用这个类的人x
和y
的值是什么。今天的练习代码可以在这里找到。如果查看代码,会发现创建了一个tsconfig.json
文件。这个文件与在第一天和第二天创建的文件完全相同,所以可以直接复制之前创建的文件,或者使用以下命令添加一个新的:
tsc --init
在day3.ts
类中,将首先创建基本的类结构。
class Point {
}
快速说明一下,可能想知道为什么没有看到任何叫做对象的东西,但一直在谈论面向对象编程。看过很多复杂的解释,但有一个非常简单的解释。当谈论一个对象时,谈论的是应用程序在运行时创建的东西;类是对象的模板,所以当创建类的一个新的实例(另一个术语是实例化类)时,实际上已经创建了一个对象。可以编写一个包含数千个类的程序;它们在实际创建实例之前是没有用的。
当创建编写的任何类的实例时,可以认为在构建这个类。为了帮助构建实例,有一个特殊的方法叫做构造函数。这个方法特别有趣,因为它帮助把实例初始化到可以使用的状态,所以它对类在实例化时发生的事情有很大的影响。由于这个方法用于构建实例,不能直接从TypeScript中调用它。唯一直接与它交互的是new
关键字。那么,构造函数是什么样子的呢?
constructor() {
}
提示:如果构造函数看起来像这样,可以删除它。如果没有在类中添加构造函数,一个默认的构造函数会自动“添加”给,看起来就像这样。不会在代码中看到它,但它就在那里。这就是为什么在第二天的代码中没有添加构造函数的原因。
在要求中,说这个类将允许添加x
和y
值来表示一个点。为此,将把这些值传递给构造函数,像这样:
constructor(x: number, y: number) {
}
有了这个,任何需要创建这个类实例的地方,都可以这样创建:
class Point {
constructor(x: number, y: number) {
}
}
const point: Point = new Point(0, 0);
注意:由于添加了一个带参数的构造函数,不再有默认构造函数的访问权限,所以被迫在这里使用带参数的构造函数。
传递了值,但实际上并没有对它们做任何事情。它们不会对任何需要它们的方法可用,因为它们只在构造函数中可见。将通过添加几个字段来存储这些值来解决这个问题。一个要求是,唯一可以改变字段值的方法是使用Offset
方法,这表明应该不能直接从类外部访问它们。为此,将引入private
关键字。private
的作用是告诉编译器这个字段只在类内部可见。
可能在想不能把所有东西都设为private
,那将是正确的。默认情况下,TypeScript使类内部的东西public
,但也可以显式地将东西设置为public
。
private
字段将看起来像这样:
private x: number;
private y: number;
如果记得,在第二天,必须在创建字段时给它们分配一个默认值。当在构造函数中给它们赋值时,编译器足够聪明,知道不必分配默认值。构造函数现在看起来像这样:
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
在下一篇文章中,将向展示TypeScript的一个方便的技巧,可以在使用构造函数签名时声明一个字段。
现在要处理其他要求。让从检查一个点是否为空的能力开始。在这里决定一个空点是x
和y
值都设置为0的点。
public IsEmpty(): boolean {
return this.x === 0 && this.y === 0;
}
接下来要写的方法是检查两个点是否相等。在这种情况下,相等意味着两个点的x
值相同,y
值也相同。由于这段代码将在类的实例中运行,只需要传入想要比较的Point
。
public IsEqual(point: Point): boolean {
return this.x === point.x && this.y === point.y;
}
通过像这样的小代码增量,可以快速添加需要的所有功能。偏移坐标的能力看起来像这样:
public Offset(x: number, y: number) {
this.x = this.x + x;
this.y = this.y + y;
}
重要说明:有一种快捷方式可以将另一个值加到现有值上。如果在代码中使用+=
,可以改变:
this.x = this.x + x;
到:
this.x += x;
而不是逐个介绍其他方法,将在这里添加整个类,这样就可以看到ToString
和Add
方法是什么样子的。到现在为止,应该对这些方法可能会做什么有一个很好的了解。
class Point {
private x: number;
private y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
public IsEmpty(): boolean {
return this.x === 0 && this.y === 0;
}
public IsEqual(point: Point): boolean {
return this.x === point.x && this.y === point.y;
}
public Add(point: Point): Point {
return new Point(point.x + this.x, point.y + this.y);
}
public ToString(): string {
return 'X is ' + this.x + ' Y is ' + this.y;
}
public Offset(x: number, y: number): void {
this.x += x;
this.y += y;
}
}
const point: Point = new Point(0, 0);
console.log('Point is empty is ' + point.IsEmpty());
// 应该是 true
point.Offset(10, 20);
console.log('Point is empty is ' + point.IsEmpty());
// 应该是 false
const offsetPoint = new Point(10, 20);
console.log('Points are equal is ' + point.IsEqual(offsetPoint));
// 应该是 true
console.log('The offset is ' + point.Add(offsetPoint).ToString());
// X is 20 and Y is 40