ES6类并不是一个全新的东西:它们主要提供更方便的语法来创建老式的构造函数,javascript的类并不像其他面向对象语言C++,java中的类,这里的类只是语法糖,实际上还是基于原型链的方式。
定义类的一种方式是使用类的申明,为了申明一个类,你可以使用class关键字空格后接一个名字。
class Rectangle { constructor(width, height) { this.width = width; this.height = height; } }函数声明和类申明一个最大的不同是,你必须先申明类才能使用,否则会抛出一个ReferenceError错误,而函数则没有这个限制。也就是说函数申明会提升而类不会,下面代码就会报错:
const p = new Rectangle(100, 30); class Rectangle { constructor(width, height) { this.width = width; this.height = height; } }类表达式是另外一种定义类的方法,类表达式可以是命名也可以是匿名的。如果是命名类表达式,这个名字只能在类体内部才能访问到。JavaScript的类也是基于原型继承的。
const Rt1 = class Rectangle { constructor(width, height) { this.width = width; this.height = height; } sayName() { console.log(Rectangle.name); } } const r1 = new Rt1(100, 20); r1.sayName(); const Rt2 = class { constructor(width, height) { this.width = width; this.height = height; } }大括号里面就是类的主体部分,在这里可以定义类的成员,如:方法或者构造函数。
类声明和类表达式的主体在严格模式下执行,即构造函数,静态和原型方法,getter和setter函数以严格模式执行。
构造函数是一个特殊的函数,一个类中有且仅有一个这样的方法,当创建一个类的对象的时候被调用。你也可以不写构造函数,但是系统会默认加上。 基类默认加上如下构造:
constructor() {}派生类默认加上如下构造:
constructor(...args) { super(...args); }使用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.hypot(dx, dy); } } const p1 = new Point(5, 5); const p2 = new Point(10, 10); console.log(Point.distance(p1, p2)); // 7.0710678118654755这里有不少坑,用之前要了解清楚,能不用就尽量不用。
class Widget { get prop() { return 'getter' } set prop(value) { console.log('setter, ' + value) } } const p = new Widget(); p.prop = 123; console.log(p.prop)下面是一个比较普遍的用法
class Foo { constructor(prop) { this.prop = prop; } static staticMethod() { return 'classy'; } prototypeMethod() { return 'prototypical'; } } const foo = new Foo(123);通过对象图来看一下它们之间的关系:
es6中的类并不是一个新的东西,它只是提供了更方便的语法去创建老式的构造函数,使用typeof Point可以看到它其实还是个函数。
在子类的构造函数中必须调用super(),同时super的调用必须在使用this之前,将上面的构造函数改为:
constructor(x, y, color) { this.color = color; super(x, y); }运行代码会报错: ReferenceError: Must call super constructor in derived class before accessing ‘this’ or returning from derived constructor
再通过下面代码看一下继承的原型链图表
class Person { constructor(name) { this.name = name; } toString() { return `Person named ${this.name}`; } static logNames(persons) { for (const person of persons) { console.log(person.name); } } } class Employee extends Person { constructor(name, title) { super(name); this.title = title; } toString() { return `${super.toString()} (${this.title})`; } } const jane = new Employee('Jane', 'CTO'); console.log(jane.toString()); // Person named Jane (CTO)