在寫類以前,咱們先看看一個概念——語法糖,剛開始聽到這個詞時,是在我面試時,當時面試官問我es6中的語法糖有哪些。毫無疑問,我答不上來,由於我連語法糖是什麼都不知道,那麼如今我就從什麼是語法糖開始來進行展開吧!
語法糖(syntactic sugar)是指編程語言中能夠更容易的表達一個操做的語法,它可使程序員更加容易去使用這門語言,操做能夠變得更加清晰、方便,或者更加符合程序員的編程習慣。用比較通俗易懂的方式去理解就是,在以前的某個語法的基礎上改變了一種寫法,實現的功能相同,可是寫法不一樣了,主要是爲了讓開發人員在使用過程當中更方便易懂。程序員
這個話題其實很大,es6中的語法糖太多了,例如經常使用的箭頭函數,解構賦值等都是語法糖,具體的能夠看看這篇文章,講得很仔細,在這裏給博主👏。es6
接下來就進入正題了,揭開es6中class的神祕面紗。首先爲何會有class的概念,在es5時期,生成實例是經過構造函數,可是若是要添加方法的話,就必須在原型上去添加,這樣構造函數new出來的實例才能夠用這個方法。就好比這樣:面試
// Person爲構造函數 function Person (name, age) { this.name = name, this.age = age } // 在構造函數的原型上添加方法 Person.prototype.getName = function () { return this.name } // 構造一個實例 var huhaha = new Person('huhaha', 21) // 在實例上調用該方法 var myName = huhaha.getName() console.log(myname) // huhaha
那麼在es6中怎麼使用class去實現它呢,先看代碼再解釋~編程
// 類中的this指向建立的實例 class Person { constructor (name, age) { this.name = name this.age = age } getName () { return this.name } } // 構造一個實例 let huhaha = new Person('huhaha', 21) // 在實例上調用該方法 const myName = huhaha.getName() console.log(myname) // huhaha
咱們能夠看到經過es6去實現,更容易理解,而且代碼量也有所減小。使用這種方式,咱們能夠清楚的明白,前面使用了class的就是一個類,那麼它就有構造實例的能力,而且constructor中放的是每一個經過該類構造出來的實例均可以得到屬性,在constructor外面放的是能夠得到的方法。
除了在寫法上的區別,class和構造函數還有一個區別就是在class中定義的方法是不可枚舉的,而在es5中原型上添加的方法是可枚舉的。還有一點就是,使用class,在建立實例的時候必須使用new,而普通的構造函數是能夠省略的。segmentfault
constructor是類的默認方法,若是在寫class時,沒有添加該方法,js引擎會默認添加這個方法。經過new去構造實例時,會自動去調用該方法,該方法默認返回的是該實例對象,可是也能夠指定返回的對象,好比下面的狀況:編程語言
class Fun { constructor () { // 改變默認返回的內容 return Object.create(null) } } let fun = new Fun() // fun不是Fun的實例 fun instanceof Fun // false
若是在類中一個屬性的前面有static關鍵詞時,就代表這個屬性是靜態屬性。靜態屬性是類的屬性,經過類構造的實例中是沒有這個屬性的,只有經過類才能夠拿到這個屬性。函數
若是在類中一個方法的前面有static關鍵詞時,就代表這個方法就是靜態方法。靜態方法的特殊性有兩點:首先,在由該類建立的實例中,是不能調用該方法的,這個方法只能經過類自己去調用;其次,若是在該方法中包含this,那麼this指向的是該類,下面的例子能夠證實這兩點:this
class Person { constructor (name, age) { this.name = name this.age = age } getName () { return this.name } static age = 42 static getAge () { return this.age } } let huhaha = new Person ('huhaha', 21) huhaha.getName() // huhaha huhaha.getAge() // TypeError: huhaha.getAge is not a function Person.getAge() // 42
咱們知道在es5中繼承的方式有不少種,最簡單的方式就是經過原型鏈進行繼承,可是就算是這種最簡單的方式也會讓人很容易混亂;爲了解決這個問題,es6中使用extends關鍵字去表示繼承,並在子類中使用super關鍵字去繼承父類的內容,下面這個例子能夠很好的代表es6中的繼承關係:es5
// Father爲父類 class Father { constructor (x, y) { this.x = x this.y = y } toString () { return 'string' } } // Child爲子類,繼承Father class Child extends Father { constructor (x, y, z) { super (x, y) // 調用Father類中的constructor(x, y) this.z = z } toString () { return super.x + super.toString() // 經過super調用Father類中定義的方法 } }
在上面的例子中,咱們能夠看到,子類繼承父類最關鍵的地方就是,須要在子類的constructor中使用super去繼承父類,它在這裏表示的是父類的構造函數,用來新建父類的this對象。這裏完成繼承的思想是,子類是經過先在父類中建立一個實例,擁有了父類中定義的屬性和方法,而後子類再添加本身的屬性和方法。這個和es5中的思想不太一致的地方在於es5中是先建立子類的this對象,而後將父類的屬性和方法添加到子類的this中。經過圖來簡單的解釋就是:spa
以前咱們有講到類的靜態屬性和靜態方法,當時說的是前面使用了static關鍵字的就是指這個類上面屬性和方法,實例是拿不到的。在這裏咱們能夠看做是這個靜態的內容,只是針對於建立實例,對於子類的繼承是不影響的,也就是說在子類中是能夠繼承到父類中的靜態屬性和方法的,甚至於咱們能夠在子類中對這些屬性和方法進行覆蓋。
咱們能夠經過Object.getPrototypeOf方法去檢測子類與父類之間的繼承關係,以下例:
// 檢測Father是否爲Child的父類 Object.getPrototypeOf(Child) === Father // true
super關鍵字是實現繼承最關鍵的內容,它有兩個身份,第一個是看成函數使用,第二個是看成對象使用,這個點其實在上面的例子也有體現到,如今咱們再來仔細說一說。
看成爲函數使用時,super表示的是父類的構造函數,咱們須要注意如下幾點:
看成爲對象去使用的時候,通常就是經過super去調用父類的屬性和方法了,可是這裏須要注意的是,使用super只能獲取到父類原型中包含的屬性和方法,也就是說後面經過實例添加的屬性和方法是獲取不到的。咱們須要注意如下幾點:
因爲時間不是很夠,後面兩塊內容下次再補充