ECMAScript6中終於引入了類的特性,在此以前只能經過其餘方法定義並關聯多個類似的對象,固然了,ES6中的類與其餘語言中的仍是不太同樣,其語法的設計實際上借鑑了JavaScript的動態性,本文檔簡單介紹一下ES6及其新特性。javascript
ES6中聲明一個類,首先編寫class關鍵字,緊跟着是類的名字,其餘部分的語法相似於對象字面量方法的簡寫形式,可是不須要子類的各元素之間使用逗號分隔,請看下面這段簡單的類聲明代碼:java
class PersonClass{ constructor(name){ this.name = name } sayName(){ return this.name } } let person = new PersonClass('xiaoMing') console.log(person.sayName()) // 'xiaoMing' console.log(person instanceof PersonType) //true console.log(person instanceof Object) //true console.log(typeof PersonClass) // function console.log(typeof PersonClass.prototype.sayName) // function
對比類聲明語法定義PersonClass的行爲與ES5以前用構造函數構建近似類過程類似,可是仍有不少差別:es6
1. 函數聲明能夠被提高,而類聲明與let聲明相似,不能被提高;真正執行聲明語句以前,他們會一直存在於臨時死區中。 2. 類聲明中的全部代碼將自動運行在嚴格模式下,並且沒法強行讓代碼脫離嚴格模式執行。 3. 在自定義類型,須要經過Object.defineProperty()方法手工指定某個方法爲不可枚舉,而在類中,全部的方法都是不可枚舉的。 4. 每一個類都有一個名爲[Constructor]]的內部方法,經過關鍵字new調用方那些不含[Constructor]]的方法會致使程序拋出錯誤。 5. 使用關鍵字new之外的方式調用類的構造函數會致使程序拋出錯誤。 6. 在類中修改類名會致使程序報錯。
類不只僅能夠經過聲明實現,還可使用類表達式 ,類表達式又分爲匿名類表達式和命名類表達式,具體語法以下所示:編程
//匿名類表達式 let PersonClass = class{ constructor(name){ this.name = name } sayName(){ console.log(this.name) } } //命名錶達式 let PersonClass = class PersonClass2{ constructor(name){ this.name = name } sayName(){ console.log(this.name) } } console.log(typeof PersonClass) // function console.log(typeof PersonClass2) // undefined
二者除了命名錶達式需在關鍵字class後添加一個標識符外,並沒有其餘差異,可是注意typeof PersonClass2 輸出的是undefined,這是由於PersonClass2只存在於類定義中,而在類的外部,其實並不存在一個名爲PersonClass2的綁定。下邊咱們用一段沒有使用關鍵字class的等價聲明來了解這背後的原理:安全
let PersonClass = (function () { const PersonClass2 = function (name) { if (typeof new.target === "undefined") { //類與構造函數差別的第五條 throw new Error("必須經過new關鍵字調用構造函數") } this.name = name } Object.defineProperty(PersonClass2.prototype, 'sayName', { value: function () { if (typeof new.target !== "undefined") { //類與構造函數差別的第四條 throw new Error("不可以使用new關鍵字調用該方法") } console.log(this.name) }, enumerable: false, writable: true, configurable: true, }) return PersonClass2 }())
外部做用域中的PersonClasss是用let聲明的,而當即表達式中的PersonClass2是用const聲明的,這也說明了爲何能夠在外部修改類名而內部卻不可修改,且PersonClass2只能在類內部使用。函數
下邊簡單介紹一下類中的幾個小特性this
首先咱們來看下ES6中是怎麼實現繼承的:prototype
class Rectangle(){ constructor(length,width){ this.length = length this.width = width } getArea(){ return this.length * this.width } } class Square extends Rectangle { constructor(length){ //等價於Rectangle.call(this,length,length) super(length,length) } } var square = new Square(3) console.log(square.getArea()) //9 console.log(square instanceof Suqare) //true console.log(square instanceof Rectangle) //true
ES5中Square繼承自Rectangle,爲了這樣作,必須建立自Rectangle.prototype的新對象重寫Square.prototype並調用Rectangle。call()方法,這些步驟很容易讓人感到困惑,並在這裏犯錯。ES6類的出現讓咱們輕鬆實現了繼承功能,使用extends關鍵字能夠指定類繼承的函數,繼承自其餘類的類被稱做派生類,若是在派生類中指定了構造函數則必需要調用super(),經過調用super()方法便可訪問基類的構造函數,原型會自動調整,若是不這樣作,程序就會報錯。若是選擇不適用構造函數,則當建立新的類實例時會自動調用super()並傳入全部參數。舉個例子,一下兩個類徹底相同:設計
class Square extends Rectangle{ //沒有構造函數 } clas Square extends Rectangle{ constructor(...args){ super(...args) } }
派生類除了上述的特徵外,還有一些其餘的特性:code