从0开始的TypeScriptの八:类
文章目錄
- 類
- 介紹
- ES5 function生成實例對象
- ES6 class生成實例對象
- 類的繼承 extend
- public private protected
- public
- private
- protected
- 只讀修飾符 readonly
- 靜態屬性
- 多態
- 抽象類和抽象方法
- 存取器 get和set
- 結束了
類
介紹
傳統的JavaScript程序使用函數和基于原型的繼承來創建可重用的組件,但對于熟悉使用面向對象方式的程序員來講就有些棘手,因為他們用的是基于類的繼承并且對象是由類構建出來的。 從ECMAScript 2015,也就是ECMAScript 6開始,JavaScript程序員將能夠使用基于類的面向對象的方式。
使用TypeScript,允許開發者現在就使用這些特性,并且編譯后的JavaScript可以在所有主流瀏覽器和平臺上運行,而不需要等到下個JavaScript版本。
class類是因為es6而產生的,在TypeScript里能夠使用es6的特性,TypeScript 除了實現了所有 es6 中的類的功能以外,還添加了一些新的用法
關于class的教程可以參考阮一峰老師的:《Class 的基本語法》
一張簡單的思維導圖來看看類與對象的關系吧:
在下圖中,父類Animal可以通過繼承的方式形成三個子類cat,dog,brid。 而秋田犬也是繼承自dog的子類。
通過new的方式,可以產生類的實例,也就是對象。 比如辛巴就是由animal動物類產生的實例,而子類也可以產生更加精確的實例對象, cat貓這一類可以產生Tom、黑貓、白貓三種對象
如果曾經學習過Java等面向對象語言,可能會對class類的概念比較熟悉了(下面這些也是比較經典的論述了):
- 類(Class):定義了一件事物的抽象特點,包含它的屬性和方法
- 對象(Object):類的實例,通過 new 生成
- 面向對象(OOP)的三大特性:封裝、繼承、多態
- 封裝(Encapsulation):將對數據的操作細節隱藏起來,只暴露對外的接口。外界調用端不需要(也不可能)知道細節,就能通過對外提供的接口來訪問該對象,同時也保證了外界無法任意更改對象內部的數據
- 繼承(Inheritance):子類繼承父類,子類除了擁有父類的所有特性外,還有一些更具體的特性
- 多態(Polymorphism):由繼承而產生了相關的不同的類,對同一個方法可以有不同的響應。
- 存取器(getter & setter):用以改變屬性的讀取和賦值行為
- 修飾符(Modifiers):修飾符是一些關鍵字,用于限定成員或類型的性質。比如 public 表示公有屬性或方法
- 抽象類(Abstract Class):抽象類是供其他類繼承的基類,抽象類不允許被實例化。抽象類中的抽象方法必須在子類中被實現
- 接口(Interfaces):不同類之間公有的屬性或方法,可以抽象成一個接口。接口可以被類實現(implements)。一個類只能繼承自另一個類,但是可以實現多個接口
ES5 function生成實例對象
JavaScript 語言中,生成實例對象的傳統方法是通過構造函數
下面的例子中,使用了原型鏈來定義方法,通過new生成實例對象
function Point(x, y) {this.x = x;this.y = y; } Point.prototype.toString = function () {return '(' + this.x + ', ' + this.y + ')'; }; var p = new Point(1, 2); // p就是Point的實例對象ES6 class生成實例對象
在es6的class類,其中具有一個名為constructor的構造方法,此方法對應上面的es5中的Point(x, y)函數方法。
如果沒有主動編寫constructor構造方法,默認會添加一個空的constructor構造方法
在通過new生成新實例時,會自動調用類中的構造函數
class Point {x: number; // 屬性 前面默認省略了public關鍵詞y: number;constructor(x: number, y: number) {this.x = x;this.y = y;}toString(): string {return '(' + this.x + ', ' + this.y + ')';} } var p = new Point(3, 4);類的繼承 extend
在class的中,可以通過extends進行繼承操作,在子類當中使用super來調用父類的構造函數和方法。 相當于初始化父類的構造函數
例子: 子類中可以單獨定義方法,子類生成的實例不僅可以調用子類中的方法,也可以調用父類的方法
class childPoint extends Point {toNumber(): number {return this.x - this.y;} } let cp = new childPoint(7, 3); console.log(cp.toString()); // (7, 3) 調用父類的方法 console.log(cp.toNumber()); // 4 調用子類自身的方法在子類中,可以使用 super 關鍵字來調用父類的構造函數和方法
constructor(x: number, y: number, age: string) {super(x, y); // 調用父類Point的x和y 初始化父類的構造函數 }子類也可以被稱為派生類,父類也可以被稱為基類或超類
public private protected
在typescript中存在公共public,私有private與受保護protected修飾符
TypeScript 可以使用三種訪問修飾符(Access Modifiers)
- public: 修飾的屬性或方法是公有的,可以在任何地方被訪問到,默認所有的屬性和方法都是 public 的
- private: 修飾的屬性或方法是私有的,不能在聲明它的類的外部訪問
- protected: 修飾的屬性或方法是受保護的,它和 private 類似,區別是它在子類中也是允許被訪問的
圖示:
public
在編寫TS類中的代碼時,成員默認都是public公共的成員。
下面的a與b是一個級別的:
class A {public a: number; // publicb : number; // publicprivate c: number; // privateprotected d: number; // protectedconstructor(a: number, b: number, c:number, d:number) {this.a = a;this.b = b;this.c = c;this.d = d;} }當實例的屬性是public時,可以被直接訪問。
let a_one = new A(7, 8, 9, 10); console.log(a_one.a);private
當成員被標記成private時,它就不能在聲明它的類的外部訪問
對于上面的例子,如果在對象中訪問private修飾的屬性c就會出現報錯。 屬性“c”為私有屬性,只能在類“A”中訪問。
console.log(a_one.c); // error: Property 'c' is private and only accessible within class 'A'.不過當在類的內部定義一個sayC方法去訪問屬性c時,就可以成功的看到屬性C的值了
sayC() {console.log(this.c); }使用對象a_one調用 a_one.sayC()。 這一步操作令我想起來閉包,是不是非常相像
protected
當成員被protected保護標記時,也不能在外部類中訪問。 對象中訪問會出現報錯:屬性“d”受保護,只能在類“A”及其子類中訪問。
與private不同的是,當使用子類繼承該類時,在子類中可以使用protected屬性。 而private修飾的屬性c會報錯
class B extends A {constructor (a:number, b:number, c:number, d:number) {super(a, b, c, d)}print () {console.log(this.d);console.log(this.c); // Property 'c' is private and only accessible within class 'A'.} }只讀修飾符 readonly
除了上面的public private protected這三種 御三家 修飾符之外,在typescript的類中,我們還可以使用readonly只讀修飾符
在之前的《從0開始的TypeScriptの四:接口Interfaces · 上》 中也對只讀屬性有過介紹
可以使用readonly關鍵字將屬性設置為只讀的。
只讀屬性必須在聲明時或構造函數里被初始化,只允許出現在屬性聲明或索引簽名或構造函數中。
下面的例子,在類中聲明了只讀屬性e,對象中可以直接打印屬性e,但是不能通過對象對只讀屬性進行修改
class C {readonly e:number = 10;constructor () {} } let cc = new C(); console.log(cc.e); cc.e = 4; // Cannot assign to 'e' because it is a read-only property.靜態屬性
可以通過 static關鍵字來創建靜態屬性。
每個實例想要訪問這個屬性的時候,都要在origin前面加上類名, 如同在實例屬性上使用this.前綴來訪問屬性一樣
下面的例子:
class D {static f:number = 15;constructor () {}say() {// console.log(this.f); // this. 是找不到靜態屬性的console.log(D.f);} } console.log(D.f); // 靜態屬性或方法不需要進行實例化即可調用注意:
多態
多態其實是屬于繼承中的內容
父類定義了一種方法,子類中各自對這個方法進行了實現。 每個子類有不同實現
***
抽象類和抽象方法
abstract 用于定義抽象類和其中的抽象方法。
抽象類和抽象方法是用來定義標準的。抽象類中的抽象方法不包含具體實現并且必須在派生類中實現, 這句話的意思是抽象類中的抽象方法在子類中必須實現
如下例子: Say類繼承自抽象類OK,如果在Say類中不實現抽象方法input就會報錯: 非抽象類“Say”不會實現繼承自“OK”類的抽象成員“input”
abstract class OK {abstract input():void; } class Say extends OK{ }所以需要在子類中實現抽象方法:
class Say extends OK{input () { } // 即使方法沒有內容也可以 }注意:抽象類是不允許被實例化的,抽象方法只能放在抽象類中
抽象類的子類是可以實例化的
let ok = new OK(); // Cannot create an instance of an abstract class. let say = new Say();存取器 get和set
使用 getter 和 setter 可以改變屬性的賦值和讀取行為
TypeScript支持通過getters/setters來截取對對象成員的訪問。 這能幫助你有效的控制對對象成員的訪問。
例子: 定義一個類,在類中使用private定義屬性_name,這樣_name就不能直接被外部訪問了,但是想要修改和讀取_name的值。 這時就可以使用存取器來設置相應的方法
class Getset {private _name: string;constructor(name:string) {this._name = name;}get name(): string {return '上將:' + this._name;}// "set" 訪問器不能具有返回類型批注set name(name: string) {this._name = name;} } let getset = new Getset("潘鳳"); console.log(getset.name); // getter getset.name = "華雄"; // setter現在就可以和public一樣去操作_name屬性了
注意:“set” 訪問器不能具有返回類型批注
結束了
終于把Typescript類的這一節學完了,累人 (當然之后類與接口結合還有東西呢)
總結
以上是生活随笔為你收集整理的从0开始的TypeScriptの八:类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用计算机弹钢琴谱,flash用键盘弹钢琴
- 下一篇: Redis(3)--哨兵模式,集群