我们之前在原型链中创建一个对象,需要使用函数的形式,然后在其原型中添加方法/属性,最后通过 new 关键字来创建实例。

那么在 ES6 之后,我们可以使用类的方式:

看上去确实清晰了很多。需要明确几点:

1、constructor 是一个构造函数,创建对象时会自动调用。即使你不写,它也默认存在。

2、所有写在 constructor 中的属性都是实例属性,是定义在实例中的。那么相对的,在 constructor 之外的属性,都是定义在类中的,也就是原型属性。

3、this 指向的是调用的实例对象,静态方法指向类本身。

4、子类使用构造器时,必须使用 super 关键字来扩展构造器,并且需要先调用 super。

6、使用 static 关键字标明类属性/方法,它们无法在实例中使用,而是通过类直接调用的。

为了深入理解,首先来看一下它们的原型结构:

看上去差不多,只是一个标记为函数,一个标记为类。

这也符合我们之前说过的原型方式,所以 class 本质上还是一个函数,只不过是一个语法糖,一个原型的另一种写法而已。

在此基础上,我们甚至可以通过原型的方式来修改/新增方法:

上面提到,constructor 属性内的是实例属性,之外的是原型属性,可以使用之前提到的检测方法来实践:

可以看到实例中自身只有 name 属性,而 print 方法确实在其原型链中可以被找到。

同时,静态属性/方法是会被继承的。

在继承过程中,经常会看到 super 关键字,它有两个作用:

1、子类调用构造函数 constructor 时,必须在构造函数内部先调用 super 关键字,然后才可以使用 this 对象。

2、子类同名方法会覆盖父类方法,这时使用 super 关键字可以调用父类方法。

所以需要在使用到 this 地方之前,调用一下 super。

作为对父类的扩展,有时候需要覆写父类,但是又需要用到父类的功能,这时可以在子类中使用 super 调用父类功能作为子类方法的一部分。

举一个例子,我们可以将上面的例子转换为:

从上面可以看到,其实 super 就是指向了原型,同时给我们提供了 this 的指向。

到此为止,基于JS的原型和原型链的内容基本就总结完毕了,学习 JS 一定要搞明白原型的内容。JS 的灵活之处就在于原型和原型链,其继承的方式也基于此,之后的类的概念也是在此基础上的。

总之,这段内容还是要多多练习领悟,才能通透。