ts除了实现所有ES6中的类功能外,还添加了一些新的方法

类(class)相关概念

  • 类(class):对事物的抽象,包含属性和方法
  • 对象(Object):类的实例,通过 new 生成
  • 面向对象的三大特性:封装、继承、多态

    • 封装(Encapsulation):将对数据操作细节隐藏,只暴露对外接口。只能通过暴露的接口来访问对象,而不能任意更改对象内部的数据
    • 继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性
    • 多态(Polymorphism):有了继承才有多态,在调用类实例方法的时候,尽量把变量视作父类类型,这样,所有子类类型都可以正常被接收
  • setter或getter:用来改变属性的读取和赋值行为
  • 修饰符:修饰符是一些关键字,用于限定成员或类的性质,如 public 表示公有属性或方法
  • 抽象类(Abstract Class):抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现。
  • 接口(Interfaces):不同类之间公有的属性或方法,可以抽象为一个接口。接口可以被类实现(implements)。一个类只能继承自另一个类,但可以实现多个接口。

ES6+中类的用法

  1. // 属性和方法
  2. class Animal {
  3. constructor(name) {
  4. this.name = name
  5. }
  6. sayHi() {
  7. return `My name is ${this.name}`
  8. }
  9. }
  10. // 类的继承
  11. class Cat extends Animal {
  12. constructor(name) {
  13. super(name) // 调用父类的 constructor(name)
  14. console.log(this.name)
  15. }
  16. sayHi() {
  17. return `Cat, ` + super.sayHi() // 调用父类的sayHi
  18. }
  19. }
  20. let c = new Cat('Miao') // Miao
  21. console.log(c.sayHi()) // Cat, My name is Miao
  22. // setter 和 getter
  23. class Animal {
  24. constructor(name) {
  25. this.name = name
  26. }
  27. get name() {
  28. reutrn 'Jack'
  29. }
  30. set name(value) {
  31. console.log('setter: ' + value)
  32. }
  33. }
  34. let a = new Animal('kitty'); // setter: Kitty
  35. a.name = 'TT' // setter: TT
  36. console.log(a.name) // Jack
  37. // 静态方法:可以通过类名直接调用的方法
  38. class Animal {
  39. static isAnimal(a) {
  40. return a instanceof Animal
  41. }
  42. }
  43. let a = new Animal('jack')
  44. Animal.isAnimal(a) //true
  45. a.isAnimal(a) // Error: a.isAnimal is not a function
  46. // 实例属性
  47. class Animal {
  48. name = 'Jack' // 实例可以直接调用
  49. constructor() {
  50. }
  51. }
  52. let a = new Animal()
  53. console.log(a.name) // Jack
  54. // 静态属性,类可以直接调用的属性
  55. class Animal {
  56. static num = 42
  57. constructor() {
  58. }
  59. }
  60. console.log(Animal.num) // 42

TypeScript中类的用法

修饰符、抽象类等

访问修饰符public、private、protected

TypeScript 可以使用三种访问修饰符,分别是:public,private, protected

  • public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是public的
  • private 修饰的属性或方法是私有的,不能在声明它的类的外部使用,包括子类
  • protected 修饰符是受保护的,和private类似,区别是它在子类中是允许被访问的。

private、protected属性示例

  1. // 示例1
  2. class Animal {
  3. public name;
  4. public constructor(name) {
  5. this.name = name
  6. }
  7. }
  8. let a = new Animal('Jack')
  9. console.log(a.name) // Jack
  10. a.name = 'Tom'
  11. console.log(a.name) // Tom
  12. // 示例2
  13. class Animal {
  14. private name;
  15. // protected name;
  16. public constructor(name) {
  17. this.name = name
  18. }
  19. get getName() {
  20. return this.name
  21. }
  22. }
  23. class Cat extends Animal {
  24. constructor(name) {
  25. super(name)
  26. console.log('cat', name)
  27. }
  28. get catName() {
  29. return this.name
  30. }
  31. }
  32. let a = new Animal('Jack')
  33. console.log(a.getName) // Jack
  34. console.log(a.name) // Error
  35. a.name = 'Tom' // Error
  36. // Property 'name' is private and only accessible within class 'Animal'.
  37. let ce = new Cat('xx')
  38. console.log(ce.name) // Error 不管是protected还是private
  39. console.log(ce.catName) // protected name 则ok,private name 则Error

private、protected用来修饰构造函数

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

  1. class Animal {
  2. public name;
  3. private constructor (name) {
  4. this.name = name;
  5. }
  6. }
  7. class Cat extends Animal { // Error 继承
  8. constructor (name) {
  9. super(name);
  10. }
  11. }
  12. let a = new Animal('Jack'); // Error 实例化

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

  1. class Animal {
  2. public name;
  3. protected constructor (name) {
  4. this.name = name;
  5. }
  6. }
  7. class Cat extends Animal { // OK
  8. constructor (name) {
  9. super(name);
  10. }
  11. }
  12. let a = new Animal('Jack'); // Error

在构造函数参数中使用修饰符

等同于类中定义该属性,使代码更简洁

  1. class Animal {
  2. // public name: string;
  3. public constructor (public name) {
  4. this.name = name;
  5. }
  6. }

只读属性关键字readonly

  1. class Animal {
  2. readonly name;
  3. public constructor(name) {
  4. this.name = name;
  5. }
  6. }
  7. let a = new Animal('Jack');
  8. console.log(a.name); // Jack
  9. a.name = 'Tom'; // Error

如果readonly和其他访问修饰符一起使用,需要写在其后面。

  1. class Animal {
  2. // public readonly name;
  3. public constructor(public readonly name) {
  4. this.name = name;
  5. }
  6. }

抽象类(abstract)

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

抽象类是不允许被实例化的

  1. abstract class Animal { // 抽象类
  2. public name;
  3. public constructor(name) {
  4. this.name = name;
  5. }
  6. public abstract sayHi(); // 抽象方法
  7. }
  8. let a = new Animal('Jack'); // Error 不允许被实例化

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

  1. abstract class Animal {
  2. public name;
  3. public constructor(name) {
  4. this.name = name;
  5. }
  6. public abstract sayHi();
  7. }
  8. class Cat extends Animal { // Error,子类没有实现抽象方法
  9. public eat() {
  10. console.log(`${this.name} is eating.`);
  11. }
  12. }
  13. let cat = new Cat('Tom');

正确示例

注意 TypeScript的编译结果中,仍然存在这个抽象类

  1. abstract class Animal {
  2. public name;
  3. public constructor(name) {
  4. this.name = name;
  5. }
  6. public abstract sayHi();
  7. }
  8. class Cat extends Animal {
  9. public sayHi() {
  10. console.log(`Meow, My name is ${this.name}`);
  11. }
  12. }
  13. let cat = new Cat('Tom');

类类型

  1. class Animal {
  2. name: string;
  3. constructor(name: string) {
  4. this.name = name
  5. }
  6. sayHi(): string {
  7. return `My name is ${this.name}`
  8. }
  9. }
  10. let a: Animal = new Animal('Jack');
  11. console.log(a.sayHi()) // My name is Jack