EcmaScript 2015 (又稱ES6)經過一些新的關鍵字,使類成爲了JS中一個新的一等公民。可是目前爲止,這些關於類的新關鍵字僅僅是創建在舊的原型系統上的語法糖,因此它們並無帶來任何的新特性。不過,它使代碼的可讀性變得更高,而且爲從此版本里更多面向對象的新特性打下了基礎。javascript
這樣作的緣由是爲了保證向後兼容性。也就是,舊代碼能夠在不作任何hack的狀況下,與新代碼同時運行。java
讓咱們回想一下在ES5中定義一個類的方式。經過不是很經常使用的Object.defineProperty
方法,我能夠定義一些只讀的屬性。es6
function Vehicle(make, year) { Object.defineProperty(this, 'make', { get: function() { return make; } }); Object.defineProperty(this, 'year', { get: function() { return year; } }); } Vehicle.prototype.toString = function() { return this.make + ' ' + this.year; } var vehicle = new Vehicle('Toyota Corolla', 2009); console.log(vehicle.make); // Toyota Corolla vehicle.make = 'Ford Mustang'; console.log(vehicle.toString()) // Toyota Corolla 2009
很簡單,咱們定義了一個有兩個只讀屬性和一個自定義toString方法的Vehicle類。讓咱們在ES6中來作同樣的事情:app
class Vehicle { constructor(make, year) { this._make = make; this._year = year; } get make() { return this._make; } get year() { return this._year; } toString() { return `${this.make} ${this.year}`; } } var vehicle = new Vehicle('Toyota Corolla', 2009); console.log(vehicle.make); // Toyota Corolla vehicle.make = 'Ford Mustang'; console.log(vehicle.toString()) // Toyota Corolla 2009
在ES6中,有兩個聲明類的方式。第一種方法叫做 類聲明,這也是咱們在上述例子中使用的方式。ide
class Vehicle { hello() { console.log('nice to meet you'); } }
有一個須要注意的地方是,類聲明與函數聲明不一樣,它不會被提高(hoisted)。例如,如下的代碼工做正常:函數
console.log(helloWorld()); function helloWorld() { return "Hello World"; }
可是,如下代碼會拋出一個異常:工具
var vehicle = new Vehicle(); class Vehicle { }
另外一個定義類的方式叫作 類表達式。它與函數表達式的運行方式徹底同樣。一個類表達式能夠是具名的也能夠是匿名的。this
var Vehicle = class { } var Vehicle = class VehicleClass { constructor() { // VehicleClass is only available inside the class itself } } console.log(VehicleClass); // throws an exception
static
關鍵字是ES6的另外一個語法糖,它使靜態方法聲明也成爲了一個一等公民。在ES5中,靜態方法就像是構造函數的一個屬性。prototype
function Vehicle() { // ... } Vehicle.compare = function(a, b) { // ... }
在使用了新的static
關鍵字後:code
class Vehicle { static compare(a, b) { // ... } }
在底層,JavaScript所作的,也只是將這個方法添加爲Vehicle構造函數的一個屬性。值得注意的是,你也能夠用一樣的語法爲類添加靜態屬性。
舊的原型繼承有時看起來讓人很是頭疼。ES6中新的extends
關鍵字解決了這個問題。在ES5,咱們是這麼作的:
function Motorcycle(make, year) { Vehicle.apply(this, [make, year]); } Motorcycle.prototype = Object.create(Vehicle.prototype, { toString: function() { return 'Motorcycle ' + this.make + ' ' + this.year; } }); Motorcycle.prototype.constructor = Motorcycle;
使用的新的extends
關鍵字,看上去就清晰多了:
class Motorcycle extends Vehicle { constructor(make, year) { super(make, year); } toString() { return `Motorcycle ${this.make} ${this.year}`; } }
super
關鍵字也能夠用於靜態方法:
class Vehicle { static compare(a, b) { // ... } } class Motorcycle extends Vehicle { static compare(a, b) { if (super.compare(a, b)) { // ... } } }
上一個例子也展現了新的super關鍵字的用法。當你想要調用父類的函數時,這個關鍵字就顯得十分好用。
在想要調用父類的構造函數時,你能夠簡單地將super關鍵字視做一個函數使用,如super(make, year)。對於父類的其餘函數,你能夠將super視做一個對象,如super.toString()。例子:kk:super指向原型對象
class Motorcycle extends Vehicle { toString() { return 'Motorcycle ' + super.toString(); } }
當在class中聲明屬性時,定義屬性名時,你可使用表達式。這個語法特性在一些ORM類庫中將會很是流行。例子:
function createInterface(name) { return class { ['findBy' + name]() { return 'Found by ' + name; } } } const Interface = createInterface('Email'); const instance = new Interface(); console.log(instance.findByEmail());
在當前,使用class關鍵字來聲明類,而不使用原型,得到的僅僅是語法上的優點。可是,這個是一個適應新語法和新實踐的好開始。JavaScript天天都在變得更好,而且經過class關鍵字,可使各類工具更好得幫助你。