class介紹

   ES6引入了Class(類)這個概念,做爲對象的模板。經過class關鍵字,能夠定義類。基本上,ES6的class能夠看做只是一個語法糖,它的絕大部分功能,ES5均可以作到,新的class寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法而已。編程

ES6的類,徹底能夠看做構造函數的另外一種寫法。瀏覽器

類的數據類型就是函數,類自己就指向構造函數。app

使用的時候,也是直接對類使用new命令,跟構造函數的用法徹底一致。函數

constructor方法

constructor方法是類的默認方法,經過new命令生成對象實例時,自動調用該方法。一個類必須有constructor方法,若是沒有顯式定義,一個空的constructor方法會被默認添加。

類的構造函數,不使用new是無法調用的,會報錯。這是它跟普通構造函數的一個主要區別,後者不用new也能夠執行。this

生成類的實例對象的寫法,與ES5徹底同樣,也是使用new命令。若是忘記加上new,像函數那樣調用Class,將會報錯。spa

與ES5同樣,實例的屬性除非顯式定義在其自己(即定義在this對象上),否則都是定義在原型上(即定義在class上)prototype

 

xy都是實例對象point自身的屬性(由於定義在this變量上),因此hasOwnProperty方法返回true,而toString是原型對象的屬性(由於定義在Point類上),因此hasOwnProperty方法返回false。這些都與ES5的行爲保持一致。3d

不存在變量提高

Class不存在變量提高(hoist),這一點與ES5徹底不一樣。code

上面代碼中,Foo類使用在前,定義在後,這樣會報錯,由於ES6不會把類的聲明提高到代碼頭部。這種規定的緣由與下文要提到的繼承有關,必須保證子類在父類以後定義。對象

Class的繼承

 Class之間能夠經過extends關鍵字實現繼承,這比ES5的經過修改原型鏈實現繼承,要清晰和方便不少。

 

上面代碼定義了一個ColorPoint類,該類經過extends關鍵字,繼承了Point類的全部屬性和方法。可是因爲沒有部署任何代碼,因此這兩個類徹底同樣,等於複製了一個Point

 

constructor方法和toString方法之中,都出現了super關鍵字,它在這裏表示父類的構造函數,用來新建父類的this對象。

子類必須在constructor方法中調用super方法,不然新建實例時會報錯。這是由於子類沒有本身的this對象,而是繼承父類的this對象,而後對其進行加工。若是不調用super方法,子類就得不到this對象。

ES5的繼承,實質是先創造子類的實例對象this,而後再將父類的方法添加到this上面(Parent.apply(this))。ES6的繼承機制徹底不一樣,實質是先創造父類的實例對象this(因此必須先調用super方法),而後再用子類的構造函數修改this

另外一個須要注意的地方是,在子類的構造函數中,只有調用super以後,纔可使用this關鍵字,不然會報錯。這是由於子類實例的構建,是基於對父類實例加工,只有super方法才能返回父類實例

類的prototype屬性和__proto__屬性 

大多數瀏覽器的ES5實現之中,每個對象都有__proto__屬性,指向對應的構造函數的prototype屬性。Class做爲構造函數的語法糖,同時有prototype屬性和__proto__屬性,所以同時存在兩條繼承鏈。

(1)子類的__proto__屬性,表示構造函數的繼承,老是指向父類。

(2)子類prototype屬性的__proto__屬性,表示方法的繼承,老是指向父類的prototype屬性。

 

上面代碼中,子類B__proto__屬性指向父類A,子類Bprototype屬性的__proto__屬性指向父類Aprototype屬性。

 這樣的結果是由於,類的繼承是按照下面的模式實現的。

 

Object.setPrototypeOf方法的實現:

 

故上面代碼等同於這裏的代碼

這兩條繼承鏈,能夠這樣理解:

做爲一個對象,子類(B)的原型(__proto__屬性)是父類(A);做爲一個構造函數,子類(B)的原型(prototype屬性)是父類的實例。

相關文章
相關標籤/搜索