ES6正式將類(Class)的概念在語法層面標準化,從此沒必要再用構造函數模擬類的行爲。而ES6引入的類本質上只是個語法糖(即代碼更爲簡潔、語義更爲清晰),其大部分功能(例如繼承、封裝和複用等)都可在ES5中實現,只不過如今能用更符合面向對象的語法來操做類。但諸如接口、protected修飾符等一些面向對象經常使用的語法,ES6沒有給出相關標準。html
在ES5時代,能夠像下面這樣模擬一個類,先聲明一個構造函數,而後在其原型上定義共享的方法,最後與new運算符組合實例化一個類。函數
function People(name) { this.name = name; } People.prototype.getName = function () { return this.name; }; var people = new People("strick"); people.getName(); //"strick"
本節接下來的內容會與這個示例有一些關聯。this
1)類聲明spa
類的建立方式與函數相似,也有兩種:類聲明和類表達式。類聲明必須包含名稱和class關鍵字,下面也建立一個People類,其主體由一對花括號包裹,它的自有屬性和方法都與前一個People類相同。注意,每一個類有且只有一個構造函數:constructor(),若是沒有顯式的聲明,那麼會有一個空的構造函數以供調用。prototype
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的類僅僅是個語法糖。code
雖然兩種類很是類似,可是ES6中的類有其獨有的特性,具體以下所列:htm
(1)類聲明和即將要講解的類表達式都不會被提高。對象
(2)類中的代碼在執行時,會強制開啓嚴格模式。blog
(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篇。
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;