TypeScript - 類



TypeScript 是面向物件的 JavaScript。TypeScript 支援面向物件的程式設計特性,例如類、介面等。在面向物件程式設計中,類是建立物件的藍圖。類封裝了物件的資料。TypeScript 為此概念提供了內建支援,稱為類。JavaScript ES5 或更早版本不支援類。TypeScript 從 ES6 獲取此特性。

建立類

使用 class 關鍵字在 TypeScript 中宣告一個類。語法如下:

語法

class class_name { 
   //class scope 
}

class 關鍵字後跟類名。命名類時必須考慮識別符號的規則。

類定義可以包含以下內容:

  • 欄位 - 欄位是在類中宣告的任何變數。欄位表示與物件相關的資料

  • 建構函式 - 負責為類的物件分配記憶體

  • 函式 - 函式表示物件可以執行的操作。它們有時也稱為方法

這些元件組合在一起被稱為類的成員。

考慮 TypeScript 中的 Person 類。

class Person {
}

編譯後,它將生成以下 JavaScript 程式碼。

//Generated by typescript 1.8.10
var Person = (function () {
   function Person() {
   }
   return Person;
}());

示例:宣告一個類

class Car { 
   //field 
   engine:string; 
 
   //constructor 
   constructor(engine:string) { 
      this.engine = engine 
   }  

   //function 
   disp():void { 
      console.log("Engine is  :   "+this.engine) 
   } 
}

此示例聲明瞭一個名為 Car 的類。該類有一個名為 engine 的欄位。宣告欄位時不使用 var 關鍵字。上面的示例為類聲明瞭一個建構函式。

建構函式是類的特殊函式,負責初始化類的變數。TypeScript 使用 constructor 關鍵字定義建構函式。建構函式是一個函式,因此可以引數化。

this 關鍵字指的是類的當前例項。這裡,引數名和類欄位名相同。因此,為了避免歧義,類欄位字首為 this 關鍵字。

disp() 是一個簡單的函式定義。請注意,這裡沒有使用 function 關鍵字。

編譯後,它將生成以下 JavaScript 程式碼。

//Generated by typescript 1.8.10
var Car = (function () {
   //constructor
   function Car(engine) {
      this.engine = engine;
   }
	
   //function
   Car.prototype.disp = function () {
      console.log("Engine is  :   " + this.engine);
   };
   return Car;
}());

建立例項物件

要建立類的例項,請使用 new 關鍵字後跟類名。語法如下:

語法

var object_name = new class_name([ arguments ])
  • new 關鍵字負責例項化。

  • 表示式的右側呼叫建構函式。如果建構函式是引數化的,則應向其傳遞值。

示例:例項化一個類

var obj = new Car("Engine 1")

訪問屬性和函式

可以透過物件訪問類的屬性和函式。使用“.”點表示法(稱為句點)來訪問類的成員。

//accessing an attribute 
obj.field_name 

//accessing a function 
obj.function_name()

示例:將它們組合在一起

class Car { 
   //field 
   engine:string; 
   
   //constructor 
   constructor(engine:string) { 
      this.engine = engine 
   }  
   
   //function 
   disp():void { 
      console.log("Function displays Engine is  :   "+this.engine) 
   } 
} 

//create an object 
var obj = new Car("XXSY1")

//access the field 
console.log("Reading attribute value Engine as :  "+obj.engine)  

//access the function
obj.disp()

編譯後,它將生成以下 JavaScript 程式碼。

//Generated by typescript 1.8.10
var Car = (function () {
   //constructor
   function Car(engine) {
      this.engine = engine;
   }
	
   //function
   Car.prototype.disp = function () {
      console.log("Function displays Engine is  :   " + this.engine);
   };
   return Car;
}());

//create an object
var obj = new Car("XXSY1");

//access the field
console.log("Reading attribute value Engine as :  " + obj.engine);

//access the function
obj.disp();

上述程式碼的輸出如下:

Reading attribute value Engine as :  XXSY1 
Function displays Engine is  :   XXSY1

類繼承

TypeScript 支援繼承的概念。繼承是程式從現有類建立新類的一種能力。擴充套件以建立新類的類稱為父類/超類。新建立的類稱為子類/子類。

類使用 extends 關鍵字繼承自另一個類。子類繼承所有屬性和方法,但私有成員和建構函式除外。

語法

class child_class_name extends parent_class_name

但是,TypeScript 不支援多重繼承。

示例:類繼承

class Shape { 
   Area:number 
   
   constructor(a:number) { 
      this.Area = a 
   } 
} 

class Circle extends Shape { 
   disp():void { 
      console.log("Area of the circle:  "+this.Area) 
   } 
}
  
var obj = new Circle(223); 
obj.disp()

編譯後,它將生成以下 JavaScript 程式碼。

//Generated by typescript 1.8.10
var __extends = (this && this.__extends) || function (d, b) {
   for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
   function __() { this.constructor = d; }
   d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var Shape = (function () {
   function Shape(a) {
      this.Area = a;
   }
   return Shape;
}());

var Circle = (function (_super) {
   __extends(Circle, _super);
   function Circle() {
      _super.apply(this, arguments);
   }
	
   Circle.prototype.disp = function () { 
      console.log("Area of the circle:  " + this.Area); 
   };
   return Circle;
}(Shape));

var obj = new Circle(223);
obj.disp();

上述程式碼的輸出如下:

Area of the Circle: 223

上面的示例聲明瞭一個 Shape 類。該類被 Circle 類擴充套件。由於類之間存在繼承關係,子類,即 Car 類,可以隱式訪問其父類的屬性,即 area。

繼承可以分類為:

  • 單繼承 - 每個類最多可以從一個父類繼承

  • 多繼承 - 一個類可以從多個類繼承。TypeScript 不支援多重繼承。

  • 多層繼承 - 下面的示例顯示了多層繼承的工作方式。

示例

class Root { 
   str:string; 
} 

class Child extends Root {} 
class Leaf extends Child {} //indirectly inherits from Root by virtue of inheritance  

var obj = new Leaf(); 
obj.str ="hello" 
console.log(obj.str)

Leaf 類透過多層繼承從 Root 和 Child 類派生屬性。

編譯後,它將生成以下 JavaScript 程式碼。

//Generated by typescript 1.8.10
var __extends = (this && this.__extends) || function (d, b) {
   for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
   function __() { this.constructor = d; }
   d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};

var Root = (function () {
   function Root() {
   }
   return Root;
}());

var Child = (function (_super) {
   __extends(Child, _super);
   function Child() {
      _super.apply(this, arguments);
   }
   return Child;
}(Root));

var Leaf = (function (_super) {
   __extends(Leaf, _super);
   function Leaf() {
      _super.apply(this, arguments);
   }
   return Leaf;
}(Child));

var obj = new Leaf();
obj.str = "hello";
console.log(obj.str);

其輸出如下:

輸出

hello

TypeScript ─ 類繼承和方法重寫

方法重寫是一種機制,子類透過它來重新定義超類的方法。下面的示例說明了這一點:

class PrinterClass { 
   doPrint():void {
      console.log("doPrint() from Parent called…") 
   } 
} 

class StringPrinter extends PrinterClass { 
   doPrint():void { 
      super.doPrint() 
      console.log("doPrint() is printing a string…")
   } 
} 

var obj = new StringPrinter() 
obj.doPrint()

super 關鍵字用於引用類的直接父類。該關鍵字可以用來引用變數、屬性或方法的超類版本。第 13 行呼叫 doWork() 函式的超類版本。

編譯後,它將生成以下 JavaScript 程式碼。

//Generated by typescript 1.8.10
var __extends = (this && this.__extends) || function (d, b) {
   for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
   function __() { this.constructor = d; }
   d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};

var PrinterClass = (function () {
   function PrinterClass() {
   }
   PrinterClass.prototype.doPrint = function () { 
      console.log("doPrint() from Parent called…"); 
   };
   return PrinterClass;
}());

var StringPrinter = (function (_super) {
   __extends(StringPrinter, _super);
	
   function StringPrinter() {
      _super.apply(this, arguments);
   }
	
   StringPrinter.prototype.doPrint = function () {
      _super.prototype.doPrint.call(this);
      console.log("doPrint() is printing a string…");
   };
	
   return StringPrinter;
}(PrinterClass));

var obj = new StringPrinter();
obj.doPrint();

上述程式碼的輸出如下:

doPrint() from Parent called… 
doPrint() is printing a string…

static 關鍵字

static 關鍵字可以應用於類的成員。靜態變數保留其值,直到程式執行結束。靜態成員由類名引用。

示例

class StaticMem {  
   static num:number; 
   
   static disp():void { 
      console.log("The value of num is"+ StaticMem.num) 
   } 
} 

StaticMem.num = 12     // initialize the static variable 
StaticMem.disp()      // invoke the static method

編譯後,它將生成以下 JavaScript 程式碼。

//Generated by typescript 1.8.10
var StaticMem = (function () {
   function StaticMem() {
   }
	
   StaticMem.disp = function () {
      console.log("The value of num is" + StaticMem.num);
   };
	
   return StaticMem;
}());

StaticMem.num = 12;     // initialize the static variable
StaticMem.disp();      // invoke the static method

上述程式碼的輸出如下:

The value of num is 12

instanceof 運算子

instanceof 運算子如果物件屬於指定的型別,則返回 true。

示例

class Person{ } 
var obj = new Person() 
var isPerson = obj instanceof Person; 
console.log(" obj is an instance of Person " + isPerson);

編譯後,它將生成以下 JavaScript 程式碼。

//Generated by typescript 1.8.10
var Person = (function () {
   function Person() {
   }
   return Person;
}());

var obj = new Person();
var isPerson = obj instanceof Person;
console.log(" obj is an instance of Person " + isPerson);

上述程式碼的輸出如下:

obj is an instance of Person True 

資料隱藏

類可以控制其資料成員對其他類成員的可見性。此功能稱為資料隱藏或封裝。

面向物件使用訪問修飾符或訪問說明符的概念來實現封裝的概念。訪問說明符/修飾符定義類的資料成員在其定義類之外的可見性。

TypeScript 支援的訪問修飾符為:

序號 訪問說明符 & 描述
1.

public

public 資料成員具有普遍的可訪問性。類中的資料成員預設是 public 的。

2.

private

私有資料成員只能被定義這些成員的類訪問。如果外部類成員試圖訪問私有成員,編譯器會丟擲錯誤。

3.

protected

受保護的資料成員可被同一類中的成員以及子類的成員訪問。

示例

讓我們來看一個例子,看看資料隱藏是如何工作的:

class Encapsulate { 
   str:string = "hello" 
   private str2:string = "world" 
}
 
var obj = new Encapsulate() 
console.log(obj.str)     //accessible 
console.log(obj.str2)   //compilation Error as str2 is private

該類有兩個字串屬性 str1 和 str2,它們分別是公共成員和私有成員。該類被例項化。該示例返回編譯時錯誤,因為私有屬性 str2 在宣告它的類之外被訪問。

類和介面

類也可以實現介面。

interface ILoan { 
   interest:number 
} 

class AgriLoan implements ILoan { 
   interest:number 
   rebate:number 
   
   constructor(interest:number,rebate:number) { 
      this.interest = interest 
      this.rebate = rebate 
   } 
} 

var obj = new AgriLoan(10,1) 
console.log("Interest is : "+obj.interest+" Rebate is : "+obj.rebate )

AgriLoan 類實現了 Loan 介面。因此,它現在繫結到該類,將其屬性 interest 作為其成員。

編譯後,它將生成以下 JavaScript 程式碼。

//Generated by typescript 1.8.10
var AgriLoan = (function () {
   function AgriLoan(interest, rebate) {
      this.interest = interest;
      this.rebate = rebate;
   }
   return AgriLoan;
}());

var obj = new AgriLoan(10, 1);
console.log("Interest is : " + obj.interest + " Rebate is : " + obj.rebate);

上述程式碼的輸出如下:

Interest is : 10 Rebate is : 1
廣告