65.9K
CodeProject 正在变化。 阅读更多。
Home

TypeScript 100天 (第3天)

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2021 年 10 月 28 日

CPOL

6分钟阅读

viewsIcon

5508

深入了解类,如何添加我们自己的构造函数,以及如何更改类外部代码是否可以访问我们的字段。

欢迎回到这个系列,我们将从基础到一些相当高级的内容来学习 TypeScript。在第 2 天,我们学习了如何使用 TypeScript 创建一个简单的类。今天,我们将更深入地探讨类,展示如何添加我们自己的构造函数,以及如何更改类外部代码是否可以访问我们的字段。

要求

我不得不承认,我有点厌倦编写简单的加法类,所以我将编写一个功能更丰富的类。今天,我将编写一个 `Point` 类。作为一名专业开发人员,我喜欢了解我的类应该做什么,所以我将为它设定以下需求。

  1. 该类将允许我添加 `x` 和 `y` 值来表示一个单独的点。
  2. 该类将为我提供一个 `IsEmpty` 方法,以便我可以确定 `x` 和 `y` 数字是否未设置为 `0,0`。
  3. 更改 `x` 和 `y` 值的唯一方法是通过 `Offset` 方法。
  4. 我将能够将一个 `Point` 添加到另一个点以获得一个新点。
  5. 我可以通过 `IsEqual` 方法确定两个点是否相等(具有相同的坐标)。
  6. 我将有一个 `ToString` 方法,它会告诉使用该类的用户 x 和 y 的值。

今天练习的代码可以在这里找到。如果您查看代码,您会发现我创建了一个 `tsconfig.json` 文件。这与我在第 2 天和第 1 天创建的文件完全相同,因此您可以复制您之前创建的文件,或使用以下命令添加新文件:

tsc --init

入门

在我的 `day3.ts` 类中,我将首先创建基本的类结构。

class Point {
}

快速题外话

您可能会想为什么我一直谈论面向对象编程,而没有看到任何叫做“对象”的东西。我已经看到过许多复杂的解释,但有一个非常简单的解释。当我们谈论一个对象时,我们谈论的是应用程序在运行时创建的东西;类是对象的模板,所以当我们创建类的实例(创建类的实例是您可能看到的另一个术语)时,我们实际上已经创建了一个对象。我们可以编写包含数千个类的程序;直到我们实际创建它们的实例之前,它们都没有用。

构造函数

当我们创建我们编写的任何类的实例时,您可以将其视为我们正在构造该类。为了帮助我们构造实例,我们有一个特殊的名为构造函数的方法。这个方法特别有趣,因为它有助于我们在开始时使用实例,因此它对类在实例化过程中发生的事情有很大的影响。由于此方法用于构造实例,因此您无法直接从 TypeScript 调用它。唯一直接与之交互的是 `new` 关键字。那么,构造函数是什么样的?

在 TypeScript 中,构造函数使用 `constructor` 关键字,如下所示:

constructor() {
}

提示:如果您的构造函数看起来像这样,您可以删除它。如果您不向类添加构造函数,它会自动为您“添加”一个看起来像这样的构造函数。您不会在代码中看到它,但它就在那里。这就是为什么我在第 2 天没有在我的代码中添加构造函数的原因。

在我的需求中,我说该类将允许我添加 `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;

如果您还记得,在第 2 天,我不得不在创建字段时为其分配一个默认值。当我在构造函数中为它们赋值时,编译器足够聪明,知道我不必分配默认值。我的构造函数现在看起来像这样:

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;

to

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()); // Should be true
point.Offset(10, 20);
console.log('Point is empty is ' + point.IsEmpty()); // Should be false
const offsetPoint = new Point(10, 20);
console.log('Points are equal is ' + point.IsEqual(offsetPoint)); // Should be true
console.log('The offset is ' + point.Add(offsetPoint).ToString()); // X is 20 and Y is 40

我们已经完成了第 3 天的代码。我承认这里有很多内容需要消化,包括创建自定义构造函数、添加作用域修饰符(`public`/`private`)以及一些替代的加法语法。请浏览 GitHub 上的代码,如果您有任何疑问,请不要害怕提问。在第 4 天,我将向您介绍 TypeScript 中的接口。如果您在 C# 或 Java 等语言中使用过接口,那么 TypeScript 使用它们的方式看起来就像奇迹。

© . All rights reserved.