面向對象是typescript的核心部分,這里先介紹下面向對象的七大原則:
- 單一原則:一個類子負責一個職責。
- 里氏替換原則:子類可以在任何地方替換它的父類。
- 依賴倒置原則:代碼要依賴於抽象的類,而不要依賴於具體的類;要針對接口或抽象類編程,而不是針對具體類編程。
- 接口隔離原則:提供盡可能小的單獨接口,而不要提供大的總接口。暴露行為讓后面的實現類知道的越少越好。
- 迪米特法則:盡量降低類與類之間的耦合。
- 開閉原則:面向擴展開放,面向修改關閉
- 組合/聚合復用原則:盡量使用合成/聚合達到復用,盡量少用繼承。原則: 一個類中有另一個類的對象。
這里不作詳細的介紹去百度面向對象的七大原則有很多文章很詳細《面向對象原則綜述》,這里簡單描述下概念;
類
es6中類的聲明:
class Demo {
constructor(a, b) {
this.a = a;
this.b = b;
}
print() {
console.log(this.a + ' ' + this.b);
}
}
typeScript中類的聲明:
class Demo {
public a:string;
public b:string;
constructor(a:string, b:string) {
this.a = a;
this.b = b;
}
print() {
console.log(this.a + ' ' + this.b);
}
}
根據單一原則,類的拆分粗細程度一定程度上是開發人的主觀選擇,舉個前端會經常遇到的例子,驗證包括姓名驗證,電話驗證,數字驗證,郵件驗證,日期驗證等等。這些驗證是放在類中處理好點還是每一種單獨聲明一個類更合適呢?放在類中處理會使驗證方法的復用率低,造成代碼冗余。每個驗證都聲明一個類又換感覺類很多。《Learning TypeScript》中提議是一個驗證聲明一個類。代碼如下:
class Email{
private email:string;
constructor(email:string){
if(this.validateEmail(email)){
this.email=email;
}else{
throw new Error("Invalid email!");
}
}
private validateEmail(email:string):boolean{
var re=/\S+@\S+\.\S+/
return re.test(email);
}
get():string{
return this.email;
}
}
class Person{
public name:string;
public age:number;
public email:Email;
constructor(name:strng,age:number,email:Email){
this.name=name;
this.age=age;
this.email=email;
}
}
這樣郵件的驗證就是在Email
中驗證格式。
繼承
typescript中繼承的實現方式為
class Person{
public name:string;
public age:number;
constructor(name:strng,age:number){
this.name=name;
this.age=age;
}
cons(text:string){
console.log(`Hi! ${this.name},${text}`);
}
}
class Man extends Person{
sex:string;
constructor(name:strng,age:number,sex:string;){
super(name,age)
this.sex=sex
}
cons(text:string){
super.cons(`man,${text}`)
}
}
let sam = new Person("li lei",12);
let tom: Person = new Man("小明",20);
例子中派生類包含了一個構造函數,它 必須調用 super(),它會執行基類的構造函數。 而且,在構造函數里訪問 this的屬性之前,我們 一定要調用 super()。 這個是TypeScript強制執行的一條重要規則。Man繼承Person,並且重寫了cons方法,方法中調用了父類的cons方法。
類屬性權限修飾符
- public(默認)公共屬性:派生類、類的實例對象都可以訪問。
class Person{
public name:string;
public age:number;
constructor(name:strng,age:number){
this.name=name;
this.age=age;
}
cons(text:string){
console.log(`Hi! ${this.name},${text}`);
}
}
- private 私有屬性:派生類、類的實例對象不可以訪問。
class Person{
private name:string;
public age:number;
constructor(name:strng,age:number){
this.name=name;
this.age=age;
}
cons(text:string){
console.log(`Hi! ${this.name},${text}`);
}
}
new Person("Cat",12).name; // 錯誤: 'name' 是私有的.
- protected 保護屬性:派生類可以訪問、類的實例對象不可以訪問。
class Person{
protected name:string;
public age:number;
constructor(name:strng,age:number){
this.name=name;
this.age=age;
}
}
class Man extends Person{
sex:string;
constructor(name:strng,age:number,sex:string;){
super(name,age)
this.sex=sex
}
cons(text:string){
console.log(`Hi! ${this.name},${text}`);
}
}
new Man("Cat",12).name; // 錯誤,name是保護屬性
- readonly 修飾符:readonly關鍵字將屬性設置為只讀的。
class Person{
readonly name:string;
public age:number;
constructor(name:strng,age:number){
this.name=name;
this.age=age;
}
}
let dad =new Person("Cat",12);
dad.name = "小明"; // 錯誤! name 是只讀的.
存取器
TypeScript支持通過getters/setters來截取對對象成員的訪問。
class Person{
private _name:string;
get name():string{
return this._name;
}
set name(name:string){
this._name=name;
}
}
let man = new Employee();
man.name='小明';
參考書籍文檔:
- 《Learning TypeScript》
- TypeScript中文網