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