ES6正式將類(Class)的概念在語法層面標準化,今后不必再用構造函數模擬類的行為。而ES6引入的類本質上只是個語法糖(即代碼更為簡潔、語義更為清晰),其大部分功能(例如繼承、封裝和復用等)均可在ES5中實現,只不過現在能用更符合面向對象的語法來操作類。但諸如接口、protected修飾符等一些面向對象常用的語法,ES6沒有給出相關標準。
## 一、創建
  在ES5時代,可以像下面這樣模擬一個類,先聲明一個構造函數,然后在其原型上定義共享的方法,最后與new運算符組合實例化一個類。
~~~
function People(name) {
this.name = name;
}
People.prototype.getName = function () {
return this.name;
};
var people = new People("strick");
people.getName(); //"strick"
~~~
  本節接下來的內容會與這個示例有一些關聯。
**1)類聲明**
  類的創建方式與函數類似,也有兩種:類聲明和類表達式。類聲明必須包含名稱和class關鍵字,下面也創建一個People類,其主體由一對花括號包裹,它的自有屬性和方法都與前一個People類相同。注意,每個類有且只有一個構造函數:constructor(),如果沒有顯式的聲明,那么會有一個空的構造函數以供調用。
~~~
class People {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
var people = new People("strick");
people.getName(); //"strick"
typeof People; //"function"
typeof People.prototype.getName; //"function"
~~~
  在代碼的最后,調用了兩次typeof運算符,由于此處的People類相當于上一個示例模擬的People類,只不過寫法不同,因此兩次運算的計算結果都是“function”,這也從側面再次印證ES6的類僅僅是個語法糖。
  雖然兩種類非常相似,但是ES6中的類有其獨有的特性,具體如下所列:
  (1)類聲明和即將要講解的類表達式都不會被提升。
  (2)類中的代碼在執行時,會強制開啟嚴格模式。
  (3)類的所有方法都不可枚舉,并且不能與new組合使用。
**2)類表達式**
  在類表達式中,名稱是可選的,但class關鍵字依然是必需的。如果包含名稱,那么叫做命名類表達式,反之,叫做匿名類表達式,如下所示。
~~~
var People = class { //匿名類表達式
};
var People = class Man { //命名類表達式
};
~~~
  命名類表達式中的名稱只能在類的內部訪問,如果在外部貿然使用,那么就會拋出未定義的錯誤。下面的例子演示了名稱的特點和局限。
~~~
var People = class Man {
getSelf() {
typeof Man; //"function"
Man.name; //"Man"
new Man().getAge(); //28
}
getAge() {
return 28;
}
};
var people = new People();
people.getSelf();
People.name; //"Man"
Man.name; //Man未定義的錯誤
~~~
  在getSelf()方法中先將typeof運算符應用于Man,然后訪問Man的name屬性,最后調用其實例的getAge()方法。在命名類的外部分別訪問People和Man的name屬性,前者能得到預期的結果,而后者卻會拋出錯誤。
  與函數表達式類似,類表達式也能立即執行,只是要像下面這樣,先在class關鍵字之前加new,然后在類的主體后面跟一對圓括號,里面的參數會傳遞給構造函數。
~~~
var people = new class {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}("strick");
people.getName(); //"strick"
~~~
## 二、成員
  類的成員既可以是普通的原型方法或自有屬性,還可以是有特殊功能的構造函數、生成器、靜態方法和訪問器屬性等,并且成員名可以是表達式。
**1)自有屬性**
  類中的自有屬性可以作為this對象的屬性,并且一般都會在構造函數中執行初始化,如下所示。
~~~
class People {
constructor() {
this.name = "strick";
}
}
~~~
**2)訪問器屬性**
  在類中的訪問器屬性,其存取語法和ES5對象字面量中的相同,也需要get和set兩個關鍵字,具體實現如下所示。
~~~
class People {
get prop() {
return `getter:${this.name}`;
}
set prop(value) {
this.name = value;
}
}
var people = new People();
people.prop = "strick";
console.log(people.prop); //"getter:strick"
~~~
  訪問器屬性還有一個便捷的地方,就是它和原型方法一樣,也能被子類繼承。
**3)計算成員名**
  類中的成員名既可以是標識符,也可以是要計算的表達式(如下代碼所示),其聲明語法和ES5對象字面量中的相同,也需要用一對方括號包裹。
~~~
var method = "getAge";
class People {
["get" + "Name"]() {
return "strick";
}
[method]() {
return 28;
}
}
var people = new People();
people.getName(); //"strick"
people.getAge(); //28
~~~
**4)生成器**
  只要在某個方法之前加上星號(\*),那么這個方法就能變為生成器,注意觀察下面代碼中的getName()方法。關于生成器的具體用法可以參考[第19篇](https://www.cnblogs.com/strick/p/10344953.html)。
~~~
class People {
*getName() {
yield "strick";
}
}
var people = new People(),
iterator = people.getName();
iterator.next(); //{value: "strick", done: false}
~~~
  如果方法的名稱是內置符號Symbol.iterator并且是一個生成器方法,那么就成功的為類創建了一個默認的迭代器,這也意味著類的實例能被for-of循環,具體實現可參考下面的代碼。
~~~
class People {
*[Symbol.iterator]() {
for (const item of [1, 2]) {
yield item;
}
}
}
var people = new People();
/********************
1
2
********************/
for(var value of people) {
console.log(value);
}
~~~
**5)靜態方法**
  ES6新增了static關鍵字,可把類中的方法(除了構造函數)定義成靜態的。要調用靜態方法只能通過類本身,而不是實例化的類,如下代碼所示。除了方法之外,static關鍵字還適用于訪問器屬性。
~~~
class People {
static getName() {
return "strick";
}
}
People.getName(); //"strick"
~~~
  雖然ES6明確提出了靜態方法,但是沒有將靜態屬性一并標準化。如果要使用靜態屬性,可以像下面這樣用變通的方式定義。
~~~
People.age = 28;
~~~
*****
> 原文出處:
[博客園-ES6躬行記](https://www.cnblogs.com/strick/category/1372951.html)
[知乎專欄-ES6躬行記](https://zhuanlan.zhihu.com/pwes6)
已建立一個微信前端交流群,如要進群,請先加微信號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