[TOC]typescript
類
類的概念
- 類 (class) : 定義了意見事物的抽象特色,包含它的屬性和方法
- 對象 (Object) :類的實例,經過
new
生成 - 面對對象 (OOP) 的三大特性: 封裝、繼承、多態
- 封裝 (Encapsulation):將對數據的操做細節隱藏起來,值暴露對外的接口。外界調用端不須要(也不可能)知道細節,就能經過對外提供的接口來訪問該對象,同時也保證了外界沒法任意更改對象內部的數據
- 繼承 (Inheritance): 子類繼承父類, 子類除了擁有父類的全部特性外, 還有一些更具體的特性
- 多態 (Polymorphism):由繼承二產生了相關的不一樣的類,對同一個方法能夠有不一樣的響應。好比
Cat
和Dog
都是繼承自Animal
, 可是分別實現了本身的eat
方法。此時針對某一個實例,咱們無需瞭解它是Cat
仍是Dog
, 就能夠直接調用eat
方法, 程序會自動判斷出來應該如何執行eat
- 存取器 (getter & setter):用來改變屬性的讀取和賦值行爲
- 修飾符 (Modifiers):修飾符是一些關鍵字,用於限定成員或類型的性質。好比
public
表示公有屬性或方法 - 抽象類(Abstract Class):抽象類是供其餘類繼承的基類,抽象類不容許被實例化。抽象類中抽象方法避稅在子類中被實現
- 接口(Interfaces):不一樣類之間公有的屬性或方法,能夠抽象成一個接口。接口能夠被類實現(implements)。一個類只能繼承自另外一個類, 可是能夠實現多個接口
類的用法
屬性和方法
使用 class
定義類, 使用 constructor
定義構造函數。函數
經過 new
生成新實例的時候, 會自動調用構造函數。this
class Animal { constructor(name) { this.name = name } sayHi() { return `My name is ${this.name}` } } let a = new Animal('jack') console.log( a.sayHi() ) // My name is Jack
類的繼承
使用 extends
關鍵字實現繼承, 子類中使用 super
關鍵字來調用父類的構造函數和方法。spa
class Cat extends Animal { constructor(name) { super(name) // 調用父類的 constructor(name) console.log(this.name) } sayHi() { return 'Meow, ' + super.sayHi() // 調用父類的 sayHi() } } let c = new Cat('Tom') // Tom console.log(c.sayHi()) // Meow, My name is Tom
存取器
使用 getter 和 setter 能夠改變屬性的賦值和讀取行爲:3d
class Animal { constructor(name) { this.name = name } get name() { return 'Jack' } set name(value) { console.log('setter: ' + value) } } let a = new Animal('Kitty'); // setter: Kitty a.name = 'Tom'; // setter: Tom console.log(a.name); // Jack
靜態屬性
到目前爲止,咱們只討論了類的實例成員,哪些僅當類被梳理化的時候纔會被初始化的屬性。code
使用 static
修飾符修飾的方法稱爲靜態方法,它們不須要實例化,而是直接經過類來調用。對象
下例中,咱們實現一個網格類, 經過 calculateDistanceFromOrigin
方法來當前點計算到原點的距離。繼承
class Grid { static origin = { x: 0, y: 0 } scale: number constructor(scale: number) { this.scale = scale } calculateDistanceFromOrigin(point: { x: number, y: number }) { let xDist = point.x - Grid.origin.x let yDist = point.y - Grid.origin.y return Math.sqrt(xDist * xDist + yDist * yDist) * this.scale } } let grid1 = new Grid(1.0) // scale => 1 let grid5 = new Grid(5.0) // scale => 5 grid1.calculateDistanceFromOrigin({x: 3, y: 4}) grid5.calculateDistanceFromOrigin({x: 3, y: 4})
Typescript 中的用法
public, private, protected接口
Typescript 中可使用三種訪問修飾符(Access Modifiers),分別是 public
, private
, protected
。ip
public
修飾的屬性或方法都是公有的, 在任何地方均可以訪問到。默認的全部屬性和方法都是public
的 。private
修飾的屬性或方法都是私有的,不能再申明它的類的外部去訪問。protected
修飾的屬性或方法是受保護的,它和private
相似, 區別是它的子類中也是容許被訪問。
🌰
class Person { public name public constructor(name) { this.name = name } } let p = new Person('Jack') console.log(p.name) // Jack p.name = 'Tom' console.log(p.name) // Tom
上面的例子中 name
被設置了 public
, 因此直接訪問 name
是被容許的。
不少時候,咱們但願有的屬性是沒法在外部直接存取。 這時候就須要用到 private
。
class Person { private name constructor(name) { this.name = name } } let p = new Person('Jack') console.log(p.name) // Jack p.name = 'Tom' // err Property 'name' is private...
使用 private
修飾的屬性或方法,在子類中也是不容許訪問的:
class Person { private name constructor(name) { this.name = name } } class Male extends Person { constructor(name) { super(name) console.log(this.name) } } // err
須要注意的是,TypeScript 編譯以後的代碼中,並無限制 private
屬性在外部的可訪問性。
而若是是用 protected
修飾, 怎容許在子類中訪問:
class Animal { protected name; public constructor(name) { this.name = name; } } class Cat extends Animal { constructor(name) { super(name); console.log(this.name); } }
抽象類
abstract
用於定義抽象類和其中的抽象方法。
什麼是抽象類?
首先抽象類不容許實例化,
abstract class Persong { public name public constructor(name) { this.name = name } public abstract sayHi() } let p = new Person('Jack') // err
上面的例子中,咱們定義了一個抽象類 Animal
,而且定義了一個抽象方法 sayHi
。在實例化抽象類的時候報錯了。
其次,抽象類中的抽象方法必須被子類實現:
abstract class Person { constructor(name) { this.name = name } public abstract sayHi() } class Male extends Persong { public eat() { console.log(`${this.name} is eating.`) } } let Jack = new Male('jack') // err Male 中 並無實現 Perosn 中的 sayHi 方法
上例中因爲 Male 中沒有實現 父類 Person 中的 sayHi 方法, 因此 編譯報錯
abstract class Person { constructor(name) { this.name = name } public abstract sayHi() } class Male extends Persong { public sayHi() { console.log(`Meow, My name is ${this.name}`) } } let Jack = new Male('jack') // success
類的類型
類的類型 與接口類似
class Person { name: sting constructor(name: sting) { this.name = name } sayHi(): string { return `My name is ${this.name}.` } } let p: Person = new Person('Jack') console.log(a.sayHi()) // My name is Jack
類與接口
類實現接口
實現(implements)是面對對象中一個很重要的概念。通常來說,一個類只能繼承自另一個類,有的時候不一樣類之間存在着一些能夠共用的特性,這時能夠把這些特性提取成接口 (interfaces),用 implements
關鍵字來實現。
舉例來講,門是一個類, 防盜門是門的子類。若是防盜門有報警功能, 這時咱們能夠簡單的給防盜門添加一個報警的方法。這時候若是有另外一類, 車。 車子也須要有報警功能。此時就能夠考慮吧報警器這個功能提取出來, 做爲一個接口,防盜門和車都去實現它。
interface Alarm { alert() } 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() } interface Light { lightOn() lightOff() } class Car implements Alarm, Light { alert() { console.log('Car alert') } lightOn() { console.log('Car light on') } lightOff() { console.log('Car light off') } }
上面的例子中, Car
實現了 Alarm
, Light
接口, 既能報警, 也能開關車燈。
接口繼承接口
接口與接口之間能夠是繼承關係:
經過使用 extends
來繼承
interface Alarm { alert() } interface Light extends Alarm { lightOn() lightOff() } class Car implements Light { alert() { console.log('Car alert') } lightOn() { console.log('Car light on') } lightOff() { console.log('Car light off') } }
接口繼承類
接口也能夠繼承類:
class Point { x: number y: number } interface Point3D extends Poing { z: number } let point3d: Point3D = {x: 1, y: 2, z: 3}
##混合類型
咱們知道,可使用接口的方式來定義一個函數須要符合的形狀:
interface SearchFunc { (source: string, subString: string): boolean } let mySearch: SearchFunc mySearch = function(source: string, subString: string) { return source.search(subString) !== -1 }
有時候,一個函數還能夠有本身的屬性和方法:
interface Counter { (start: number): string interval: number reset(): void } function getCounter(): Counter { let counter = <Counter>function (start: number) { } counter.interval = 123 counter.reset = function () { } return counter } let c = getCounter() c(10) c.reset() c.interval = 5.0