1. 程式人生 > 實用技巧 >TypeScript の 類 介面

TypeScript の 類 介面

建立一個物件

class Person{
    public name:string;
    public age:number;
    constructor(name:string, age:number){
        this.name = name;
        this.age = age;
    }
}
let a = new Person("測試", 15); 
console.log(a.name  + " --- " + a.age)

繼承

class NewPerson extends Person{
    public sex: number;
    constructor(sex: number){
        this.sex = sex;
    }
}

由圖可見,上面的繼承是不正常的,所以這裡需要呼叫其super方法

class NewPerson extends Person{
    public sex: number;
    constructor(name:string,age:number,sex: number){
        super(name,age);
        this.sex = sex;
    }
}

私有屬性

class PrivatePerson{
    private name:string;
    constructor(name:string){
        this.name = name;
    }
}

let c = new PrivatePerson("wz");
console.log(c.name) // 提示報錯

這個就是私有屬性,那麼我們該怎麼訪問這個私有屬性呢?
class PrivatePerson{
    private name:string;
    constructor(name:string){
        this.name = name;
    }
    get getName(){
        return this.name;
    }
}

let c = new PrivatePerson("wz");
console.log(c.getName)

通過上述的get修飾的屬性(看起來更像一個方法),便可以獲取到私有屬性,最後可以通過c.getName

獲取到

get獲取屬性,那麼是否有set設定屬性呢???
class PrivatePerson{
    private name:string;
    constructor(name:string){
        this.name = name;
    }
    get getName(){
        return this.name;
    }
    set setName(name: string){
        this.name = name
    }
}

let c = new PrivatePerson("wz");
console.log(c.getName)
c.setName = "哈哈"; 
console.log(c.getName)

通過上面set的案例,我們應該清楚的看到,其實getset修飾的都不是方法,而是屬性,因為方法的呼叫fn(),而這個看起來更像是屬性的寫法,所以這裡注意c.setName = "哈哈",既然這樣,為了美觀,我們將上面的進行一個修改

class PrivatePerson{
    private _name:string;
    constructor(name:string){
        this._name = name;
    }
    get name(){
        return this._name;
    }
    set name(name: string){
        this._name = name
    }
}

let c = new PrivatePerson("wz");
console.log(c.name)
c.name = "哈哈"; 
console.log(c.name)

這樣看起來就完全一樣了

私有屬性作用是什麼呢?
實現單例模式
class SimpleObject {
    //靜態方法中只能呼叫靜態變數
    private static simpleInfo: SimpleObject;
    
    //私有化建構函式,讓其無法被外界`new`出來
    private constructor(){}
    
    //提供公共的靜態的獲取例項方法
    public static getInstance(){
        //判斷例項是否存在
        if(!this.simpleInfo){
            //不存在就例項化一個
            this.simpleInfo = new SimpleObject();
        }
        //返回例項
        return this.simpleInfo;
    }
}

以上的單例模式很簡單,但是也需要注意幾個小點

  • 因為我們需要實現"單例模式",所以必須要限制例項化的方式,只能由我們內部提供,所以將建構函式私有化,在前面加上private
  • 獲取例項方法: 因為我們把建構函式constructor私有化了,所以外部無法使用new關鍵字例項化物件,我們必須要提供的獲取例項方法getInstance必須可以在不例項化的情況下呼叫,所以這個方法必須使用static修飾
  • 靜態方法只能訪問靜態的資料,所以這裡的例項simpleInfo也是靜態的,並且為了不讓其被外部直接呼叫,所以加上private
實現部分屬性只能獲取,而無法修改
  • 私有屬性實現
class PriPerson{
    private _name:string;
    constructor(name :string){
        this._name = name;
    }
    get name(){
        return this._name
    }
}
let e = new PriPerson("一個人");
console.log(e.name) 
e.name = "不可修改" //報錯
  • readonly實現
class PriPerson{
    public readonly name:string;
    
    constructor(name :string){
        this.name = name;
    } 
}
let e = new PriPerson("一個人");
console.log(e.name)
e.name = "不可修改" //報錯

抽象類

有時候需要分類,同一類事物有著公共的特性,公共的方法(但是每個之間實現不同),這個時候我們就可以定義個抽象類,抽出相同的,相同的方法

abstract class Animal{ 
    getEatOrgan(){
        return "嘴";
    }

    abstract eat():string;
} 
class People extends Animal{
    eat(){
        return "使用手抓吃飯";
    } 
}
class Pig extends Animal{
    eat(){
        return "使用嘴拱著吃";
    }
} 
let animals : [string, string] = ["man", "pig"]; 
animals.forEach((animal) => {
    let unknownAnimal:Animal;
    unknownAnimal = animal === "man" ? new People() : new Pig(); 
    console.log("吃飯通用器官:" + unknownAnimal.getEatOrgan(), 
    "各自吃飯方式: " + unknownAnimal.eat());  
}) 

結果

介面的繼承

我們常常會定義一些介面,用於型別定義及檢測,像下面一樣

interface Student{
    name:string,
    age:number
}

interface Teacher{
    name:string,
    sex:string
}

const sayHello = (user) => {
    console.log(user.name)
}
let st: Student ={
    name: '張珊',
    age:18
} 
let te :Teacher = {
    name:"歷史",
    sex:"男"
}
sayHello(st);
sayHello(te);

但是我們發現,sayHello中引數user的推斷型別是

這個不是我們想要的,所以我們去定義這個user的型別,用什麼呢?是Student還是Teacher,當然是我全都要了

 const sayHello = (user: Student | Teacher) => {
    console.log(user.name)
}
思考,當我們新建物件的時候,這個引數型別是不是一直在新增呢?

這個時候就需要使用我們的介面繼承(提取出相同的屬性,方法,然後其他子類繼承該介面)

interface Person{
    name:string
}

interface Student extends Person{ 
    age:number
}

interface Teacher  extends Person{ 
    sex:string
}

const sayHello = (user:Person) => {
    console.log(user.name)
}
let st: Student ={
    name: '張珊',
    age:18
} 
let te :Teacher = {
    name:"歷史",
    sex:"男"
}
sayHello(st);
sayHello(te);