构造函数

我们来看一个简单的 Animal 类,这里我们能很清晰地看到 Animal 拥有 5 个成员 catName、dogName 属性,一个构造函数,以及 catSay、dogSay 方法。

  1. class Animal {
  2. catName: string;
  3. dogName: string;
  4. constructor(catName: string, dogName: string) {
  5. this.catName = catName;
  6. this.dogName = dogName;
  7. }
  8. catSay() {
  9. console.log(`Mow, I'm ${this.catName}`);
  10. }
  11. dogSay() {
  12. console.log(`Wong, I'm ${this.dogName}`);
  13. }
  14. }

在我们 Animal 类中,我们引用其中任意成员时都用了 this ,这表示我们访问的是类的成员。

public、private、protected 修饰符

public

在其他一些语言中,针对类的成员需要用修饰符来指定成员的可见性。而我们上述代码中并没有使用 public 修饰符来指定成员的可见性,这是因为在 TS 中,类的成员默认为 public。所以以下代码和上述代码语义上是一致的。

class Animal {
  public catName: string;
  public dogName: string;

  public constructor(catName: string, dogName: string) {
    this.catName = catName;
    this.dogName = dogName;
  }

  public catSay() {
    console.log(`Mow, I'm ${this.catName}`);
  }

  public dogSay() {
    console.log(`Wong, I'm ${this.dogName}`);
  }
}

private

private 表示私有成员,当类的成员被标记为 private 时,它将不能在类的外部被访问到。我们为 Animal 类增加一个 owner 的私有成员。

class Animal {
  public catName: string;
  public dogName: string;
  private owner: string;

  public constructor(owner: string, catName: string, dogName: string) {
    this.owner = owner;
    this.catName = catName;
    this.dogName = dogName;
  }
  public catSay() {
    console.log(`Mow, I'm ${this.catName}, I love ${this.owner}`);
  }
  public dogSay() {
    console.log(`Wong, I'm ${this.dogName} I love ${this.owner}`);
  }
}

const animal = new Animal("Evan", "Lily", "Coco");

console.log(animal.owner); // [ts] Property 'owner' is private and only accessible within class 'Animal'. [2341]

当我们尝试从 Animal 的实例 animal 中访问 owner 的时候,会报错并提示 owner 是私有成员。

protected

protected 表示受保护的成员,行为与 private 相似,同样不允许从类的外部访问,但可以在类的派生类中被访问,我们看如下代码。

class Animal {
  public catName: string;
  public dogName: string;
  protected owner: string;

  public constructor(owner: string, catName: string, dogName: string) {
    this.owner = owner;
    this.catName = catName;
    this.dogName = dogName;
  }
  public catSay() {
    console.log(`Mow, I'm ${this.catName}, I love ${this.owner}`);
  }
  public dogSay() {
    console.log(`Wong, I'm ${this.dogName} I love ${this.owner}`);
  }
}

class FindAnimalOwner extends Animal {
  public findOwner() {
    // 此时受保护的 Animal 成员 owner 可以被访问
    console.log(`Owner is ${this.owner}`);
  }
}
const findAnimalOwner = new FindAnimalOwner("Ivan", "Lily", "Coco");

console.log(findAnimalOwner.findOwner()); // Owner is Ivan

静态成员

我们在上文中讨论的都是类的实例成员,仅当类被实例化时才会被初始化。除了实例成员,在 TS 中,类还拥有静态成员,静态成员存在于类上面而不是类的实例上。
我们给 Animal 增加 catAge 和 dogAge 两个静态属性。

class Animal {
  public catName: string;
  public dogName: string;
  private owner: string;
  static catAge: number = 5;
  static dogAge: number = 3;

  public constructor(owner: string, catName: string, dogName: string) {
    this.owner = owner;
    this.catName = catName;
    this.dogName = dogName;
  }
  public catSay() {
    // 通过 Animal.catAge 来访问 catAge, catAge是存在于类本身的属性,而不是存在于实例上。
    console.log(
      `Mow, I'm ${this.catName}, I love ${this.owner}, I'm ${
        Animal.catAge
      } years old.`
    );
  }
  public dogSay() {
    console.log(
      `Wong, I'm ${this.dogName} I love ${this.owner}, I'm ${
        Animal.dogAge
      } years old.`
    );
  }
}

const animal = new Animal("Evan", "Lily", "Coco");