[轉]JavaScript ES6 class指南

[轉]JavaScript ES6 class指南

前言

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關鍵字,可使各類工具更好得幫助你。

相關文章
相關標籤/搜索