1. 程式人生 > 實用技巧 >Class(類)分享 第四節

Class(類)分享 第四節

一、基礎

// es6 普通的一個類
// 建構函式為例項新增成員,類的所有方法都定義在類的prototype屬性,即原型上面。
class Animal {
 name
 constructor(name, age){
  this.name = name
 }
	move(distance){
 	console.log(`The speed of ${this.name} is ${distance}m/s`)
 }
}
let a = new Animal("Tom")
console.log(a.move(5))

//ts, 成員,引數,函式返回值加上型別檢查,例項加上類型別
class Animal { // 聲明瞭類的例項的型別
 name: string
 constructor(name: string){
  this.name = name
 }
 move(distance: number): void{
 	console.log(`The speed of ${this.name} is ${distance}m/s`)
 }
}
let a: Animal = new Animal("Tom")
console.log(a.move(5))

二、繼承

使用extends關鍵字實現繼承。子類中如果有構造方法,必須使用super關鍵字來呼叫父類的建構函式

class Animal {
 name: string;
 age: number;
 constructor(name: string, age: number) {
  this.name = name
  this.age = age
  }
 move(distance: number): void {
  console.log(`The speed of ${this.name} is ${distance}m/s`)
  }
}
​
class Cat extends Animal {
 catkind
 // 子類有建構函式,必須使用super呼叫父類構造方法
 constructor(name: string, age: number, catkind: string) {
  super(name, age)
  this.catkind = catkind
  }
 // 重寫move
 move(distance: number): void {
  console.log("cat walking...");
  super.move(distance)
  }
}
​
class Dog extends Animal {
 dogkind
 constructor(name: string, age: number, dogkind: string) {
  super(name, age)
  this.dogkind = dogkind
  }
 move(distance: number): void {
  console.log("dog walking...");
  super.move(distance)
  }
}
​
let cat1: Cat = new Cat("Tom", 5, "persian")
console.log(`${cat1.name} is ${cat1.age} years old,its kind is ${cat1.catkind} cat`)
console.log(cat1.move(5))
​
let dog1: Dog = new Dog("jack", 3, "Husky")
console.log(`${dog1.name} is ${dog1.age} years old,its kind is ${dog1.dogkind} dog`)
console.log(dog1.move(10))

三、public private 和 protected

  • public:預設所有的成員和方法都是public。修飾的成員和方法是公開的,可以在任何地方被訪問到
  • private: 修飾的成員和方法是私有的的,只能在宣告它的類的內部被訪問, 不允許被例項和子類訪問
  • protected:修飾的成員和方法是受保護的,只能在宣告它的類和子類的內部被訪問, 不允許被例項訪問
// 1. public
class Animal {
 public name: string;
 public constructor(name: string) {
  this.name = name;
  }
 public move(distance: number): void {
    console.log(`The speed of ${this.name} is ${distance}m/s。`)
  }
}
​
let cat1 = new Animal("Tom")
console.log(cat1.name)
console.log(cat1.move(5))
​
// 2.1 private-成員
class Animal {
 private name: string;
 public constructor(name: string) {
  this.name = name;
  }
 public move(distance: number): void {
    console.log(`The speed of ${this.name} is ${distance}m/s。`)
  }
}
​
let cat1 = new Animal('Tom');
console.log(cat1);
console.log(cat1.name); // error 例項不能訪問
console.log(cat1.move(85)); // 類內部可以訪問
​
​
class Cat extends Animal{
  public constructor(name: string){
    super(name);
  }
 public say() {
  console.log(`${this.name} say miao~miao~`);
  }
} 
​
let cat2 = new Cat('haha');
console.log(cat2.name) // error 在子類的例項中也不能被訪問
​
// 2.2 private-建構函式
// 建構函式修飾為 private 時,該類不允許被繼承或者例項化
class Animal {
 public name;
 private constructor(name) {
  this.name = name;
  }
}
class Cat extends Animal { // error a. 不能被繼承
 constructor(name) {
  super(name);
  }
}
let cat1 = new Animal('Jack'); // error b. 不能被例項化
​
// 3.1 protected-成員
class Animal {
 protected name: string;
 public constructor(name: string) {
  this.name = name;
  }
 public move(distance: number): void {
    console.log(`The speed of ${this.name} is ${distance}m/s。`)
  }
}
​
let cat1 = new Animal('Tom');
console.log(cat1.move(85)); // 類內部可以訪問
console.log(cat1.name); // error  例項不能訪問
​
class Cat extends Animal{
  public constructor(name: string){
    super(name);
  }
  public say() {
    console.log(`${this.name} say miao~miao~`); // 在子類中可以訪問
  }
} 
let cat2 = new Cat('haha');
console.log(cat2.say())
console.log(cat2.name) // error 在子類的例項中也不能被訪問
​
// 3.2 protected-建構函式
// 建構函式修飾為 protected 時,該類只允許被繼承
class Animal {
 public name;
 protected constructor(name) {
  this.name = name;
  }
}
class Cat extends Animal {
 constructor(name) {
  super(name);
  }
}
​
let a = new Animal('Jack'); // error 不能被例項化

四、readonly

使用readonly關鍵字將成員設定為只讀的。 只讀成員必須在宣告時或建構函式裡被初始化。

class Animal {
 readonly name: string;
 readonly age: number = 18; // 宣告時初始化
 public constructor(name: string) {
  this.name = name; // 建構函式裡初始化
  }
}
​
let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom'; // error 只讀

注意如果readonly和其他訪問修飾符同時存在的話,需要寫在其後面。

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

五、引數屬性

一般,我們先宣告類的成員和建構函式內賦值。通過引數屬性,我們將宣告和賦值合併起來。

// 一般
class Animal {
 public name: string;
 public constructor(name: string) {
  this.name = name;
  }
}
let a = new Animal('Jack');
console.log(a.name); // Jack
​
// 引數屬性
class Animal {
 // public name: string; // 省略
 public constructor(public name: string) {
    // 引數屬性,必須有修飾符  public,protected,private或readonly
  // this.name = name;  // 可省略
  }
}
let a = new Animal('Jack');
console.log(a.name); // Jack

六、存取器

使用 getter 和 setter 可以改變屬性的賦值和讀取行為。當類成員上定義存取器時,就不能使用正常成員宣告

class Animal {
 // name: string  成員宣告
 constructor(name: string) {
  this.name = name;
  }
 get name() { // 存取器
  return 'Jack';
  }
 set name(value) {
  console.log('setter: ' + value);
  }
}
​
let a = new Animal('Kitty');
a.name = 'Tom';
console.log(a.name);

七、靜態屬性

可以通過static定義建立類的靜態成員和方法,這些成員和方法存在於類的本身而不是類的例項上。只能通過類名訪問,不能被建構函式例項化

class Animal {
 static firstWord = "hello";
 constructor(public name: string){}
 sayHi(){
  console.log(Animal.firstWord)
  }
 static isAnimal(animal: Animal): void {
  console.log(animal instanceof Animal);
  }
}
let a = new Animal("Tom")
​
console.log(Animal.firstWord)
Animal.isAnimal(a)
​
console.log(a.firstWord) // error, 例項不能訪問
a.isAnimal(a) // error
a.sayHi()

八、抽象類

abstract用於定義抽象類和其中的抽象方法。顧名思義,抽象類和抽象方法是對對一些物件的屬性和行為進行高度抽象,一般不包含具體實現細節,所以基類使用。所以,抽象類是不允許被例項化的。其次,抽象類中的抽象方法必須被子類實現,因為一般不包含實現細節。

abstract class Animal {
 name: string;
 constructor(name: string) {
  this.name = name;
  } 
 abstract move(distance: number): void;
}
​
class Cat extends Animal {
 constructor(name: string) {
  super(name)
  }
 move(distance: number): void { // 必須實現基類的抽象方法
  console.log(`The speed of ${this.name} is ${distance}m/s`)
  }
}
​
let a = new Animal('Jack'); // error,不允許例項化
let cat = new Cat('Tom');
cat.move(5)

九、類和介面

一般來講,一個類只能繼承自另一個類,有時候不同類之間可以有一些共有的屬性和行為,這時候就可以把這些通用屬性和方法提取成介面(interfaces),用implements關鍵字來實現。

舉例,門是一個類,防盜門是它的子類。車也是一個類,車和防盜門都有報警功能,將其提取成一個報警方法。作為一個介面,防盜門和車等都可以實現它。

interface Alarm {
  alert(): void;
}
​
class Door {
}
​
class SecurityDoor extends Door implements Alarm {
  alert() {
    console.log('SecurityDoor alert');
   }
}
​
class Car implements Alarm {
  alert() {
    console.log('Car alert');
   }
}

一個類只能繼承自一個類,但也可以實現多個介面

interface Alarm { // 報警
alert(): void;
}
​
interface controlDoor { // 開關門
openDoor(): void;
closeDoor(): void;
}
​
class Car implements Alarm, controlDoor {
alert() {
console.log('Car alert');
}
openDoor() {
console.log('Car door open');
}
closeDoor() {
console.log('Car door close');
}
}

類定義會建立兩個東西:類的例項型別和一個建構函式。 因為類可以創建出型別,所以你能夠在允許使用介面的地方使用類。

class Point {
    x: number;
    y: number;
}
interface Point3d extends Point { // 類可以被當作介面使用
    z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};