類是對對象的抽象,描述了對象的特征和行為,而對象就是類的實例。ES6引入了類的概念(相關內容可參考[ES類](https://www.cnblogs.com/strick/p/10364124.html)和[ES6類的繼承](https://www.cnblogs.com/strick/p/10364274.html)兩節),TypeScript在此基礎上,不僅根據ES7等規范完善了類的語法,還添加了許多其它語法。而在使用TypeScript的類時,不必關心兼容性問題,因為這些工作已由編譯器完成。
  下面是一個簡單的類,包含3個成員:帶private修飾符的name屬性、構造函數constructor()和getName()方法,最后一句使用new運算符創建了Person類的實例,并調用了一次它的構造函數。
~~~js
class Person {
private name: string;
constructor(name: string) {
this.name = name;
}
getName() {
return this.name;
}
}
let worker = new Person("strick");
~~~
  編譯后的代碼如下所示,通過傳統的構造函數和基于原型的繼承來模擬一個類。
~~~js
var Person = /** @class */ (function() {
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() {
return this.name;
};
return Person;
})();
var worker = new Person("strick");
~~~
## 一、屬性
  在ES6中,實例屬性(即自有屬性)得作為this對象的屬性存在,并且一般都會在構造函數中執行初始化,而TypeScript允許在類中直接定義實例屬性,如下所示。
~~~js
//ES6中的實例屬性
class Person {
constructor(name: string) {
this.name = name;
}
}
//TypeScript中的實例屬性
class Person {
name: string;
}
~~~
  不僅如此,TypeScript還提供了存在于類本身上的靜態屬性,即不需要實例化就能調用的屬性。在下面的示例中,為age屬性添加了static關鍵字,使其成為靜態屬性,通過類的名稱就能直接調用它。
~~~js
class Person {
static age: number;
}
Person.age = 28;
~~~
## 二、修飾符
  修飾符是用于限定成員或類型的一種符號,TypeScript包含三個訪問修飾符:public、private和protected,以及一個成員修飾符:readonly。
**1)public**
  在TypeScript中,成員默認都是public的,即在派生類(也叫子類)或類的外部都能被訪問。在下面的示例中,Person類中的name屬性是公共的,Programmer類繼承了Person類。注意,當派生類包含一個構造函數時,必須調用super()方法,執行基類(即父類)的構造函數,并且該方法得在訪問this對象之前調用。
~~~js
class Person {
public name: string;
constructor(name: string) {
this.name = name;
}
}
class Programmer extends Person {
constructor(name: string) {
super(name);
}
}
~~~
  在初始化Person類或Programmer類之后,就能通過創建的實例來訪問name屬性,如下所示。
~~~js
let person = new Person("strick");
person.name; //"strick"
let programmer = new Programmer("freedom");
programmer.name; //"freedom"
~~~
**2)private**
  當成員被修飾為private時,只能在類的內部訪問它,例如在基類Person中聲明一個私有的age屬性,在類的實例或派生類的實例中訪問age屬性都會在編譯階段報錯,如下所示。
~~~js
class Person {
private age: number;
}
person.age; //錯誤
programmer.age; //錯誤
~~~
  當構造函數被修飾為private時(如下所示),包含它的類既不能實例化,也不能被繼承。
~~~js
class Person {
private constructor(name: string) {
this.name = name;
}
}
~~~
**3)protected**
  此修飾符與private的行為類似,只是有一點不同,即在派生類中還是可以訪問它的,例如在基類Person中聲明一個受保護的school屬性,在派生類中就能訪問到它,如下所示(省略了基類的構造函數)。
~~~js
class Person {
protected school: string;
}
class Programmer extends Person {
constructor(name: string) {
super(name);
this.school = "university";
}
}
~~~
  當構造函數被修飾為protected時(如下所示),包含它的類不能實例化,但可以被繼承。
~~~js
class Person {
protected constructor(name: string) {
this.name = name;
}
}
~~~
**4)readonly**
  當成員被修飾為readonly時,它就變成只讀的,只能在聲明時或構造函數里初始化,其它地方對它的修改都是禁止的,如下所示。
~~~js
class Person {
readonly gender: string = "女"; //正確
constructor() {
this.gender = "男"; //正確
}
}
let person = new Person();
person.gender = "女"; //錯誤
~~~
  當readonly與其它修飾符一起使用時,需跟在它們后面,如下所示。
~~~js
class Person {
protected readonly gender: string;
}
~~~
## 三、參數屬性
  參數屬性可以便捷的在構造函數中聲明并初始化一個類的屬性,此類參數會與三個訪問修飾符或readonly組合使用,如下所示。
~~~js
class Person {
constructor(public name: string) { }
}
~~~
  構造函數中的name是一個參數屬性,相當于在Person類中聲明一個name屬性,并在構造函數中為其初始化,如下所示。
~~~js
class Person {
public name: string;
constructor(name: string) {
this.name = name;
}
}
~~~
## 四、抽象類
  抽象類是供其它派生類繼承的基類,它與接口一樣,不能被實例化,但可以包含成員的實現細節。在聲明一個類時,如果包含abstract關鍵字,那么這就是一個抽象類,如下所示,當對其進行實例化時,會在編譯時報錯。
~~~js
abstract class Person { }
let person = new Person(); //錯誤
~~~
  在抽象類中,會聲明一個或多個帶abstract類修飾符的抽象方法,它們只有名稱,不包含實現細節,可與訪問修飾符組合使用,如下所示。
~~~js
abstract class Person {
protected abstract work(): void
}
~~~
  派生類中必須實現繼承的抽象方法(如下所示),否則會在編譯階段報錯。
~~~js
class Programmer extends Person {
public work(): void {
console.log("code");
}
}
~~~
*****
> 原文出處:
[博客園-TypeScript躬行記](https://www.cnblogs.com/strick/category/1561745.html)
[知乎專欄-TypeScript躬行記](https://zhuanlan.zhihu.com/pwts2019)
已建立一個微信前端交流群,如要進群,請先加微信號freedom20180706或掃描下面的二維碼,請求中需注明“看云加群”,在通過請求后就會把你拉進來。還搜集整理了一套[面試資料](https://github.com/pwstrick/daily),歡迎瀏覽。

推薦一款前端監控腳本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不僅能監控前端的錯誤、通信、打印等行為,還能計算各類性能參數,包括 FMP、LCP、FP 等。
- ES6
- 1、let和const
- 2、擴展運算符和剩余參數
- 3、解構
- 4、模板字面量
- 5、對象字面量的擴展
- 6、Symbol
- 7、代碼模塊化
- 8、數字
- 9、字符串
- 10、正則表達式
- 11、對象
- 12、數組
- 13、類型化數組
- 14、函數
- 15、箭頭函數和尾調用優化
- 16、Set
- 17、Map
- 18、迭代器
- 19、生成器
- 20、類
- 21、類的繼承
- 22、Promise
- 23、Promise的靜態方法和應用
- 24、代理和反射
- HTML
- 1、SVG
- 2、WebRTC基礎實踐
- 3、WebRTC視頻通話
- 4、Web音視頻基礎
- CSS進階
- 1、CSS基礎拾遺
- 2、偽類和偽元素
- 3、CSS屬性拾遺
- 4、浮動形狀
- 5、漸變
- 6、濾鏡
- 7、合成
- 8、裁剪和遮罩
- 9、網格布局
- 10、CSS方法論
- 11、管理后臺響應式改造
- React
- 1、函數式編程
- 2、JSX
- 3、組件
- 4、生命周期
- 5、React和DOM
- 6、事件
- 7、表單
- 8、樣式
- 9、組件通信
- 10、高階組件
- 11、Redux基礎
- 12、Redux中間件
- 13、React Router
- 14、測試框架
- 15、React Hooks
- 16、React源碼分析
- 利器
- 1、npm
- 2、Babel
- 3、webpack基礎
- 4、webpack進階
- 5、Git
- 6、Fiddler
- 7、自制腳手架
- 8、VSCode插件研發
- 9、WebView中的頁面調試方法
- Vue.js
- 1、數據綁定
- 2、指令
- 3、樣式和表單
- 4、組件
- 5、組件通信
- 6、內容分發
- 7、渲染函數和JSX
- 8、Vue Router
- 9、Vuex
- TypeScript
- 1、數據類型
- 2、接口
- 3、類
- 4、泛型
- 5、類型兼容性
- 6、高級類型
- 7、命名空間
- 8、裝飾器
- Node.js
- 1、Buffer、流和EventEmitter
- 2、文件系統和網絡
- 3、命令行工具
- 4、自建前端監控系統
- 5、定時任務的調試
- 6、自制短鏈系統
- 7、定時任務的進化史
- 8、通用接口
- 9、微前端實踐
- 10、接口日志查詢
- 11、E2E測試
- 12、BFF
- 13、MySQL歸檔
- 14、壓力測試
- 15、活動規則引擎
- 16、活動配置化
- 17、UmiJS版本升級
- 18、半吊子的可視化搭建系統
- 19、KOA源碼分析(上)
- 20、KOA源碼分析(下)
- 21、花10分鐘入門Node.js
- 22、Node環境升級日志
- 23、Worker threads
- 24、低代碼
- 25、Web自動化測試
- 26、接口攔截和頁面回放實驗
- 27、接口管理
- 28、Cypress自動化測試實踐
- 29、基于Electron的開播助手
- Node.js精進
- 1、模塊化
- 2、異步編程
- 3、流
- 4、事件觸發器
- 5、HTTP
- 6、文件
- 7、日志
- 8、錯誤處理
- 9、性能監控(上)
- 10、性能監控(下)
- 11、Socket.IO
- 12、ElasticSearch
- 監控系統
- 1、SDK
- 2、存儲和分析
- 3、性能監控
- 4、內存泄漏
- 5、小程序
- 6、較長的白屏時間
- 7、頁面奔潰
- 8、shin-monitor源碼分析
- 前端性能精進
- 1、優化方法論之測量
- 2、優化方法論之分析
- 3、瀏覽器之圖像
- 4、瀏覽器之呈現
- 5、瀏覽器之JavaScript
- 6、網絡
- 7、構建
- 前端體驗優化
- 1、概述
- 2、基建
- 3、后端
- 4、數據
- 5、后臺
- Web優化
- 1、CSS優化
- 2、JavaScript優化
- 3、圖像和網絡
- 4、用戶體驗和工具
- 5、網站優化
- 6、優化閉環實踐
- 數據結構與算法
- 1、鏈表
- 2、棧、隊列、散列表和位運算
- 3、二叉樹
- 4、二分查找
- 5、回溯算法
- 6、貪心算法
- 7、分治算法
- 8、動態規劃
- 程序員之路
- 大學
- 2011年
- 2012年
- 2013年
- 2014年
- 項目反思
- 前端基礎學習分享
- 2015年
- 再一次項目反思
- 然并卵
- PC網站CSS分享
- 2016年
- 制造自己的榫卯
- PrimusUI
- 2017年
- 工匠精神
- 2018年
- 2019年
- 前端學習之路分享
- 2020年
- 2021年
- 2022年
- 2023年
- 2024年
- 日志
- 2020