iT邦幫忙

2022 iThome 鐵人賽

DAY 15
0
Modern Web

Hello TypeScript 菜鳥系列 第 15

Day 14. TypeScript Class 類別:基本語法

  • 分享至 

  • xImage
  •  

Class是JavaScript ES6以後出來的語法糖,今天大部分的內容也和JavaScript差不多,如果對JavaScript Class熟悉的話,加上型別就能掌握Class在TypeScript的基本用法了。

在TypeScript的語法裡,Class加上型別的最基本用法如下:

class Person {
	id: number;
	first_name: string;
	last_name: string;
	birth_year: number;
	
	constructor(id: number, first_name: string, last_name: string, birth_year: number) {
		this.id = id;
		this.first_name = first_name;
		this.last_name = last_name;
		this.birth_year = birth_year;
	}
	
	getName(): string {
		return `${this.first_name} ${this.last_name}`;
	});
	
	
	getBirthYear(): number {
		return this.birth_year;
	}
	
	
	introduce(): string {
		return `My name is ${first_name}.`;
	}
}


const Bob = new Person(1234567, 'Bob', 'Jonason', 1989);

console.log(Bob.getName());	 // Bob Jonason
console.log(Bob.birth_year);	 // Compile error
console.log(Bob.getBirthYear()); // 1989

Inheritance 繼承

任一類別都可以透過繼承(inheritance)的方式去重複使用特定類別擁有的屬性和方法,這裡創建一個SuperHero類別繼承剛剛的Person類別,在TypeScript一樣是使用 extends 關鍵字去繼承:

class SuperHero extends Person {

	constructor(id: number, first_name: string, last_name: string, birth_year: number, title: string, ability: string){
		super(id, first_name, last_name, birth_year);
		this.title = title;
		this.ability = ability;
	}
	
	introduce(): void {
		return `${super.introduce()} I'm a ${this.title}`
	}
}

const superMan = new SuperHero('00000000', 'Clark', 'Kent', 1938, 'super man', 'fly')

這個範例使用ES6的語法,為了讓SuperHero繼承Person的語法,所以在constructor裡用 super() 去使用父類別(parent class)Person既有的屬性和方法。

同時,這裡也用了 method overriding 的方式去覆寫Person類別的 introduce,以及使用 super.introduce() 語法去存取Person類別既有的 introduce 函式回傳值。


Static properties and methods 靜態屬性和方法

上述class的屬性和方法都是專指特定物件(或說實例, instance)本身的方法和屬性,例如 first_name = 'Bob' 是屬於Bob物件的屬性和其屬性值。

但是不同物件(實例)之間可能也會有一些共用的屬性和方法,而跟單一物件(實例)自身沒有關係,這時可以用 static 關鍵字來創造這些共用屬性和方法:

class Person {
	static person_count: number = 0;
	id: number;
	first_name: string;
	last_name: string;
	birth_year: number;

	constructor(id: number, first_name: string, last_name: string, birth_year: number) {
		this.id = id;
		this.first_name = first_name;
		this.last_name = last_name;
		this.birth_year = birth_year;
		
		++person_count;
	}
	
	static getPersonCount(): number{
		return Person.person_count;
	}
	
	getName(): string {
		return `${this.first_name} ${this.last_name}`;
	});
	
	
	getBirthYear(): number {
		return this.birth_year;
	}
	
	introduce(): string {
		return `My name is ${first_name}.`
	}
}


Getters & Setters

在前面的例子,我們都是用 get... 開頭的函式去存取class裡面的 privateprotected 屬性,但也有其他既能保護屬性,也能加上一些判斷避免屬性值被惡意竄改的方式,以下使用 getter 重寫和 getBirthyear 相同的方法,並且使用 setter 加上修改 birth_year 的方法:

class Person {
	static person_count: number = 0;

	constructor(id: number, first_name: string, last_name: string, birth_year: number) {
		this.id = id;
		this.first_name = first_name;
		this.last_name = last_name;
		this.birth_year = birth_year;
		
		++person_count;
	}
	
	static getPersonCount(): number{
		return Person.person_count;
	}
	
	getName(): string {
		return`${this.first_name} ${this.last_name}`;
	});
	
	
	/*
	    getBirthYear(): number {
		    return this.birth_year;
	    }
	*/
	
	get birthYear(): number {
		return this._birth_year;
	}
	
	set birthYear(birth_year: number) {
		if(birth_year >= 0) {
			this._birth_year = birth_year;
		} else {
			throw new Error("Error: Invalid birth year");
		}
	}
	
	introduce(): string {
		return `My name is ${first_name}.`
	}
}

const Bob = new Person(1234567, 'Bob', 'Jonason', 1989);
console.log(Bob.birthYear);	// 1989

Bob.birthYear = -1;	// Error: Invalid birth year
Bob.birthYear = 1990;
console.log(Bob.birthYear);	// 1990

這個範例不允許負的出生年(或說西元前的出生年),因此加上 >=0 的限制來避免。

而從範例也可以看出相較於寫一般函式,getter和setter的寫法更為簡潔有力,也確實能保護屬性。

今天談的大都是在JavaScript就有的語法,只是加上型別讓這些語法可以在TypeScript通過編譯器,並強化class本身的屬性和方法,明天才會專注於討論TypeScript在class新增的語法。


參考資料
TypeScript Tutorial


上一篇
Day 13. TypeScript Function 函式
下一篇
Day 15. TypeScript Class 類別:Member visibility、readonly、abstract
系列文
Hello TypeScript 菜鳥31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言