5.类

我们知道 JSES6 中引入了“类”(class) 的概念 ,在 TS 中,这部分完全可以直接拿过来使用,不过稍有变化。


定义类

class Chinese {

   // 声明属性
   name: string
   sex: string

   // 注意:构造函数无返回值,所以不能像普通函数那样在返回值注解部分编写类型注解
   constructor(name: string, sex: string) {
      // 属性要先声明后使用
       this.name = name;
       this.sex = sex
   }

   // 一般方法的声明
   say(word: string): void {
       console.log(this.name, word);
   }
}

// 获取实例
let c1 = new Chinese('如花', '男')
console.log(c1);
c1.say('帅哥')

类的继承

class Chinese {

   // 声明属性
   name: string
   sex: string

   // 注意:构造函数无返回值,所以不能像普通函数那样在返回值注解部分编写类型注解
   constructor(name: string, sex: string) {
       this.name = name;
       this.sex = sex
   }

   // 一般方法的声明
   say(word: string): void {
       console.log(this.name, word);
   }
}

// 继承父类
class HeNan extends Chinese {
   // 重写父类的方法
   say(): void {
       super.say('我从子类中调用的啊')
       console.log('子类的内容啊');
       
   }
}

let h1 = new HeNan('张思睿', '男')
console.log(h1);
h1.say()

前面的部分,和 ES6 中的 class 的使用基本一样,只是多了类型注解。

使用“类”作为类型注解类型

// 声明一个类
class Cat {
   // 声明属性
   name: string
   constructor(name: string) {
       this.name = name;
   }
   say(): void {
       console.log(this.name);
   }
}
// 声明一个类
class Dog {
   name: string
   constructor(name: string) {
       this.name = name;
   }
}

let c1 = new Cat('小猫')
let d1 = new Dog('小狗')
// 指定该变量的注解类型为Cat类
let someone: Cat;
someone = c1
//将其它类的实例赋值给someone时会报错(如果Dog类和Cat类结构一样的话,也能编译通过)。
someone = d1

多态

多态就是指多种形态。当存在继承关系的时候,对于同一个父类型的不同子类型的实例而言,它们既属于子类型的,也属于父类型,当调用这些实例的相同方法时,可能会产生不同的行为。

// 声明一个类
class Cat {

   // 声明属性
   name: string
   constructor(name: string) {
       this.name = name;
   }

   say(): void {
       console.log(this.name);
   }
}
// 定义一个子类
class Tiger extends Cat {
   say(): void {
       console.log(this.name + '咯咯叫');
   }
}

// 定义一个子类
class PetCat extends Cat {
   say(): void {
       console.log(this.name + '咪咪叫');
   }
}
//
let animal: Cat;
let t1: Cat;
let p1: Cat;
animal = new Cat('猫科动物')
animal.say()
// t1既属于Tiger类型的数据,也属于Cat类型的数据
t1 = new Tiger('老虎')
t1.say()
// p1既属于PetCat类型的数据,也属于Cat类型的数据
p1 = new PetCat('小猫咪')
p1.say()

Tiger的实例,既属于Tiger类型的数据,也属于Cat类型的数据,PetCat的实例,既属于PetCat类型的数据,也属于Cat类型的数据。上面的 t1p1 虽然都是 Cat 类型的数据,但是当调用相同的方法时,还是表现出了不同的行为,这就叫多态。

public、private、protected 修饰符

这三个修饰符,主要使用开控制类的属性和方法访问性的,默认所有属性都是使用 public 修饰。

  • public:公开的,用来定义可以在任何地方自由的访问成员

  • protected:受保护的,用来定义可以在本类或者子类中访问的成员

  • private:私有的,用来定义仅可以在本类内部访问的成员

    class Cat {
       public name: string;
       // 定义一个私有属性,仅能在该类中被访问
       private girl: string = '如花'

       constructor(name: string) {
           this.name = name
       }

       // 定义一个可以在任何位置访问的方法
       public say(): void {
           console.log('我们说点啥呢');
           // 在类的内部访问私有属性
           console.log(this.girl);
           // 在类的内部访问受保护的成员方法
           this.money()
       }

       // 定义一个受保护的方法,可以在本类中访问,也可以在子类中访问
       protected money(): void {
           console.log('我们很有钱');
       }
    }

    let c1 = new Cat('小花猫')
    // 对于 public 修饰的成员,可以在任何地方使用他们
    console.log(c1.name);
    c1.say()
    class Tiger extends Cat {
       public run(): void {
           // 访问使用protected修饰的成员
           this.money()
           // 访问使用private修饰的成员(会报错)
           console.log(this.girl);
       }
    }

    let t1 = new Tiger('老虎')
    t1.run()

只读属性

可以使用 readonly 关键字将属性设置为只读。 只读属性必须在声明时或构造函数里被初始化

class Cat {
   // 设置只读属性
   public readonly name: string;
   constructor(name: string) {
       this.name = name
   }
}

let c1 = new Cat('如花')
console.log(c1.name);
// 当修改只读属性的时候,会报错
c1.name = '翠花'

参数属性

默认情况下,我们要在类中定义成员属性,必须要在类的前面定义属性名,然后在构造函数中通过 this.属性名 = 某个变量 的形式对其进行初始化。其实还是比较麻烦的。我们如果在构造函数的形参上使用 readonlypublicprotectedprivate 等修饰,则无需进行之前那种比较繁琐的操作。

class Cat {
   constructor(public name: string, readonly sex: string) {}
}

let c1 = new Cat('如花', '男')
console.log(c1.name);
console.log(c1.sex);

gettersetter

这部分和 ES6 中的一样,不在过多说明。


静态属性

这部分和 ES6 中的一样,不在过多说明。

微信 遇到疑问可加微信进行反映