class 和继承

ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

基本形式

class Person {
// constructor方法是类的默认方法
constructor (name, age) {
// 这里的 this 代表实例对象
this.name = name;
this.age = age;
}
showName () {
// 每个方法后面不用加逗号,方法名前面不能加function
return `这个人的名字是:${this.name}`
}
}
// 调用的时候必须用 new 命令
let p1 = new Person ('libin', 18); // 可以只传第一个参数
p1.showName(); // 这个人的名字是:libin
// 类本身指向构造函数
Person === Person.prototype.constructor // true
// 实例上的方法就是类的原型上的方法
p1.showName === Person.prototype.showName // true
// 在类的实例上面调用方法就是调用原型上的方法
p1.constructor === Person.prototype.constructor // true
// 但是实例上定义的方法只属于当前实例
p1.showAge = function () {
return `这个人的年龄是:${this.age}`
}
p1.showAge(); // 这个人的年龄是:18
p1.showAge === Person.prototype.showAge // false
let p2 = new Person ('小明', 10);
p2.showAge(); // 报错:p2.showAge is not a function
// 继承
class Student extends Person {
// 这里什么都不写就可以直接继承父类的属性和方法
}
let s1 = new Student('leo', 8);
s1.showName(); // 这个人的名字是:leo
class Student extends Person {
constructor (name, age, type) {
// super() 必须写在前面,然后才是子类自己的方法
super(name, age);
this.type = type;
}
showType () {
super.showName(); // 这个人的名字是:leo 调用父类的方法
return `这个人的类型是:${this.type}`
}
}
let s2 = new Student('leo', 8, '学生');
s2.showType(); // 这个人的类型是:学生

说明:

  1. 类上所有的方法都是定义在类的 prototype 属性上面
  2. 不存在变量提升,必须先定义类再调用
  3. 类的方法内部如果含有 this ,它默认指向类的实例,可以通过在类的 constructor 内部 this.fn = this.fn.bind(this) 来解决
  4. 类的方法前面加关键字 static 则不会被实例继承,可以通过类来调用,这称为静态方法。静态方法如果包含 this 关键字则这个this指向当前类,而不是实例
  5. 类的静态方法可以被子类继承
  6. 通过 super 关键字表示父类的构造函数 super() 和指向父类的原型对象 super.fn()
  7. 子类的方法可以覆盖父类的同名方法

ES5 的继承实质上是先创造子类的实例对象 this,然后再将父类的方法添加到 this 上面 Parent.apply(this) 。ES6 的继承则是先将父类实例对象的属性和方法加到 this 上面(所以必须先调用 super() 方法),然后再子类的构造函数修改 this。

参考:

阮一峰ES6教程