Typescript 类 (十五)

传统方法中,Javascript 通过构造函数实现类的概念而在 ES6 中,引入了 class

类的概念

属性和方法

使用 class 定义类,使用 constructor 定义构造函数

通过 new 生成新实例的时候,会自动调用构造函数


class Animal {

  public name;
  constructor(name){
    this.name = name;
  }
  sayHi(){
    return `My name is ${this.name}`
  }
}

let a = new Animal('jack')

console.log(a.sayHi())

类的继承

使用 extends 关键字实现继承,子类中使用 super 关键字来调用父类的构造函数和方法

class Cat extends Animal {
  constructor(name) {
    super(name)
    console.log(name)
  }
  sayHi() {
    return 'Meow' + super.sayHi() //调用父类的sayHi()
  }
}

let c = new Cat('Tom') //Tom
console.log(c.sayHi()) // meow,My name is Tom

存储器

使用 setter 和 getter 可以改变属性的赋值和读取

class Animal {
  constructor(name) {
    this.name = name
  }
  get name() {
    return 'Jack'
  }
  set name(value) {
    console.log('setter: ' + value)
  }
}

let a = new Animal('Kitty') // setter: Kitty
a.name = 'Tom' // setter: Tom
console.log(a.name) // Jack

静态方法

使用 static 修饰符修饰的方法叫做静态方法,它们不需要实例化,而是直接通过类来调用

class Animal {
  static isAnimal(a) {
    return a instanceof Animal
  }
}

let a = new Animal('Jack')
Animal.isAnimal(a) // true
a.isAnimal(a) // TypeError: a.isAnimal is not a function

Typescript 中类的用法

public private 和 protected

Typescript 有三种访问修饰符 分别是 public ,private,和 protected

  • public 是公有的,任何地方都会被访问到,默认所有的属性和方法都是 public

  • private 修饰的属性或者方法都是私有的,不能再声明它的类的外部访问

  • protected 修饰的属性或者方法是受保护的,但是在子类中能被访问,而外部不能使用


class Animal {
  public name;
  public constructor(name) {
    this.name = name;
  }
}

let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';
console.log(a.name); // Tom

上面的例子中,name 被设置成了 public,所以直接访问实例的 name 是允许的

很多时候,我们希望有的属性是无法直接存储的,这个时候就需要 private


class Animal {
  private name;
  public constructor(name) {
    this.name = name;
  }
}

let a = new Animal('Jack');
console.log(a.name);
a.name = 'Tom';

// index.ts(9,13): error TS2341: Property 'name' is private and only accessible within class 'Animal'.
// index.ts(10,1): error TS2341: Property 'name' is private and only accessible within class 'Animal'.

而如果是用 protected 修饰,则允许在子类中访问


class Animal {
  protected name;
  public constructor(name) {
    this.name = name;
  }
}

class Cat extends Animal {
  constructor(name) {
    super(name);
    console.log(this.name);
  }
}

而当构造函数修饰为 private 时,该类不允许被继承或者实例化


class Animal {
  public name;
  private constructor(name) {
    this.name = name;
  }
}
class Cat extends Animal {
  constructor(name) {
    super(name);
  }
}

let a = new Animal('Jack');

// index.ts(7,19): TS2675: Cannot extend a class 'Animal'. Class constructor is marked as private.
// index.ts(13,9): TS2673: Constructor of class 'Animal' is private and only accessible within the class declaration.

当构造函数修饰为 protected 时候,该类只允许被继承


class Animal {
  public name;
  protected constructor(name) {
    this.name = name;
  }
}
class Cat extends Animal {
  constructor(name) {
    super(name);
  }
}

let a = new Animal('Jack');

// index.ts(13,9): TS2674: Constructor of class 'Animal' is protected and only accessible within the class declaration.

参数属性

修饰符和 readonly 还可以使用在构造函数参数中,等同于类中定义该属性同时给该属性赋值,代码更简洁


class Animal {
  // public name: string;
  public constructor(public name) {
    // this.name = name;
  }
}

readonly

只读关键字,只允许出现在属性声明或者索引签名或者构造函数中


class Animal {
  readonly name;
  public constructor(name) {
    this.name = name;
  }
}

let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';

// index.ts(10,3): TS2540: Cannot assign to 'name' because it is a read-only property.

但是要注意的就是如果 readonly 和其他访问修饰符同时存在,需要写在后面

下面的例子就是 public readonly


class Animal {
  // public readonly name;
  public constructor(public readonly name) {
    // this.name = name;
  }
}

抽象类

abstract 用于定义抽象类和其中的抽象方法

  • 抽象类不允许被实例化

abstract class Animal {
  public name;
  public constructor(name) {
    this.name = name;
  }
  public abstract sayHi();
}

let a = new Animal('Jack');

// index.ts(9,11): error TS2511: Cannot create an instance of the abstract class 'Animal'.

上面的例子中,我们定义了一个抽象类 Animal,并且定义了一个抽象的方法 sayHi,在实例化的时候报错了

  • 抽象类中的抽象方法必须被子类实现

abstract class Animal {
  public name;
  public constructor(name) {
    this.name = name;
  }
  public abstract sayHi();
}

class Cat extends Animal {
  public eat() {
    console.log(`${this.name} is eating.`);
  }
}

let cat = new Cat('Tom');

// index.ts(9,7): error TS2515: Non-abstract class 'Cat' does not implement inherited abstract member 'sayHi' from class 'Animal'.

上面的例子中 我们定义了一个类 Cat 继承了抽象类 Animal,但是没有实现抽象方法 sayHi,所以编译报错了

下面是一个正确使用抽象类的例子


abstract class Animal {
  public name;
  public constructor(name) {
    this.name = name;
  }
  public abstract sayHi();
}

class Cat extends Animal {
  public sayHi() {
    console.log(`Meow, My name is ${this.name}`);
  }
}

let cat = new Cat('Tom');

类的类型

给类加上 Typescript 的类型很简单,和接口类似

class Animal {
  name: string
  constructor(name: string) {
    this.name = name
  }
  sayHi(): string {
    return `My name is ${this.name}`
  }
}

let a: Animal = new Animal('Jack')
console.log(a.sayHi()) // My name is Jack

文章作者: 雾烟云
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 雾烟云 !
  目录