詳解es6中的class語法糖

  在寫類以前,咱們先看看一個概念——語法糖,剛開始聽到這個詞時,是在我面試時,當時面試官問我es6中的語法糖有哪些。毫無疑問,我答不上來,由於我連語法糖是什麼都不知道,那麼如今我就從什麼是語法糖開始來進行展開吧!

什麼是語法糖?

  語法糖(syntactic sugar)是指編程語言中能夠更容易的表達一個操做的語法,它可使程序員更加容易去使用這門語言,操做能夠變得更加清晰、方便,或者更加符合程序員的編程習慣。用比較通俗易懂的方式去理解就是,在以前的某個語法的基礎上改變了一種寫法,實現的功能相同,可是寫法不一樣了,主要是爲了讓開發人員在使用過程當中更方便易懂。程序員

es6中的語法糖有哪些?

  這個話題其實很大,es6中的語法糖太多了,例如經常使用的箭頭函數,解構賦值等都是語法糖,具體的能夠看看這篇文章,講得很仔細,在這裏給博主👏。es6

es6中的class

es5和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

class基本語法

constructor函數

  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

class的繼承

  咱們知道在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

  • es6中的實現思路

es6中的實現思路

  • es5中的實現思路

es5中的的實現思路

  以前咱們有講到類的靜態屬性和靜態方法,當時說的是前面使用了static關鍵字的就是指這個類上面屬性和方法,實例是拿不到的。在這裏咱們能夠看做是這個靜態的內容,只是針對於建立實例,對於子類的繼承是不影響的,也就是說在子類中是能夠繼承到父類中的靜態屬性和方法的,甚至於咱們能夠在子類中對這些屬性和方法進行覆蓋。

檢驗父類的方法

  咱們能夠經過Object.getPrototypeOf方法去檢測子類與父類之間的繼承關係,以下例:

// 檢測Father是否爲Child的父類
Object.getPrototypeOf(Child) === Father // true

super關鍵字

  super關鍵字是實現繼承最關鍵的內容,它有兩個身份,第一個是看成函數使用,第二個是看成對象使用,這個點其實在上面的例子也有體現到,如今咱們再來仔細說一說。

做爲函數使用

  看成爲函數使用時,super表示的是父類的構造函數,咱們須要注意如下幾點:

  1. 在子類中必須包含super
  2. 子類中的super只能在構造函數中使用
  3. super內部的this是指向子類的,這一點能夠看這裏
做爲對象使用

  看成爲對象去使用的時候,通常就是經過super去調用父類的屬性和方法了,可是這裏須要注意的是,使用super只能獲取到父類原型中包含的屬性和方法,也就是說後面經過實例添加的屬性和方法是獲取不到的。咱們須要注意如下幾點:

  1. 在靜態方法中使用時,super指向的是父類而不是父類的原型對象
  2. 在普通方法中使用時,super指向的是父類的原型對象而不是父類自己
  3. 在靜態方法中經過super去調用父類的方法時,this指向的是子類,而不是子類的實例
  4. 在使用super時,咱們必須顯式地代表做爲對象使用仍是做爲函數使用

使用es5實現es6中的class

關於class的小練習

  因爲時間不是很夠,後面兩塊內容下次再補充

相關文章
相關標籤/搜索