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
上面两个例子中定义的类有一个不一样的地方。咱们为了享受新的get
语法带来的好处,因此只是将make
和year
定义成了普通的属性。这使它们能够被外部所改变。若是你确实须要一个严格的私有属性,仍是请继续使用defineProperty
。ide
在ES6中,有两个声明类的方式。第一种方法叫做 类声明,这也是咱们在上述例子中使用的方式。函数
class Vehicle() { }
有一个须要注意的地方是,类声明与函数声明不一样,它不会被提高(hoisted)。例如,如下的代码工做正常:工具
console.log(helloWorld()); function helloWorld() { return "Hello World"; }
可是,如下代码会抛出一个异常:oop
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
关键字后:
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 { static compare(a, b) { if (super.compare(a, b)) { // ... } } }
上一个例子也展现了新的super
关键字的用法。当你想要调用父类的函数时,这个关键字就显得十分好用。
在想要调用父类的构造函数时,你能够简单地将super
关键字视做一个函数使用,如super(make, year)
。对于父类的其余函数,你能够将super
视做一个对象,如super.toString()
。例子:
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
关键字,可使各类工具更好得帮助你。
https://strongloop.com/strongblog/an-introduction-to-javascript-es6-classes/