部分来自JavaScript ES6 class指南、 1.定义类 让我们回想一下在ES5中定义一个类的方式。通过不是很常用的Object.defineProperty方法,我可以定义一些只读的属性。
function Vehicle1(make, year) { Object.defineProperty(this, 'make', { get: function() { return make; } }); Object.defineProperty(this, 'year', { get: function() { return year; } }); } Vehicle1.prototype.toString = function() { return this.make + ' ' + this.year; } var vehicle1 = new Vehicle1('Toyota Corolla', 2009); console.log(vehicle1.make); // Toyota Corolla vehicle1.make = 'Ford Mustang'; console.log(vehicle1.toString()) // Toyota Corolla 2009
很简单,我们定义了一个有两个只读属性和一个自定义toString方法的Vehicle类。让我们在ES6中来做一样的事情: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。2.类声明 类声明是定义类的一种方式,就像下面这样,使用 class 关键字后跟一个类名(这里是 Polygon),就可以定义一个类。
class Polygon { constructor(height, width) { this.height = height; this.width = width; } }
3.变量提升 类声明和函数声明不同的一点是,函数声明存在变量提升现象,而类声明不会。也就是说,你必须先声明类,然后才能使用它,否则代码会抛出 ReferenceError 异常,像下面这样:
var p = new Polygon(); // ReferenceError class Polygon {}
4.类表达式 类表达式是定义类的另外一种方式。在类表达式中,类名是可有可无的。如果定义了类名,则该类名只有在类体内部才能访问到。匿名的
var Polygon1 = class { constructor(height, width) { this.height = height; this.width = width; } };
命名的var Polygon2 = class Polygon { constructor(height, width) { this.height = height; this.width = width; } };
注意: 类表达式和类声明一样也不会有提升的现象。5.原型方法
class Polygon3 { constructor(height, width) { this.height = height; this.width = width; } get area() { return this.calcArea() } calcArea() { return this.height * this.width; } } const square = new Polygon3(10, 10); console.log(square.area);// 100
6.静态方法 static 关键字用来定义类的静态方法。静态方法是指那些不需要对类进行实例化,使用类名就可以直接访问的方法,需要注意的是静态方法不能被实例化的对象调用。静态方法经常用来作为工具函数。class Point { constructor(x, y) { this.x = x; this.y = y; } static distance(a, b) { const dx = a.x - b.x; const dy = a.y - b.y; return Math.sqrt(dx*dx + dy*dy); } } const p1 = new Point(5, 5); const p2 = new Point(10, 10); console.log(Point.distance(p1, p2));
7.类继承 使用 extends 创建子类extends 关键字可以用在类声明或者类表达式中来创建一个继承了某个类的子类。
class Animal { constructor(name) { this.name = name; } speak() { console.log(this.name + ' makes a noise.'); } } class Dog extends Animal { speak() { console.log(this.name + ' barks.'); } } var d = new Dog('Mitzie'); d.speak(); Animal2 (name) { this.name = name; } Animal2.prototype.speak = function () { console.log(this.name + ' makes a noise.'); } class Dog2 extends Animal2 { speak() { super.speak(); console.log(this.name + ' barks.'); } } var d2 = new Dog2('Mitzie'); d2.speak(); Animal3 = { speak() { console.log(this.name + ' makes a noise.'); } }; class Dog3 { constructor(name) { this.name = name; } speak() { super.speak(); console.log(this.name + ' barks.'); } } Object.setPrototypeOf(Dog3.prototype, Animal3); var d3 = new Dog3('Mitzie'); d3.speak();
8.Species 你可能想要数组类 MyArray 返回的是 Array 对象。这个 species 模式能让你重写默认的构造器。例如,当使用像 map() 这样的方法来返回默认的构造器时,你想要这个方法返回父级的 Array 对象,而不是 MyArray 对象。Symbol.species 能实现: