本文深入对比 ES5 与 ES6 的继承实现。ES5 通过原型链和 apply 先创建子类实例再绑定父类方法;ES6 则先创建父类实例再修改子类指针。重点解析 super 关键字的双重用法及静态方法特性,并说明 ES6 能继承原生构造函数而 ES5 不能的原因。
继承方式
ES5 prototype 继承
ES5 的继承依赖于原型链机制,即通过构造函数与 [[prototype]] 属性的指向关系来实现。具体而言,子类的 prototype 属性被设置为父类对象的一个实例。这意味着子类的原型对象中包含了指向父类原型对象的指针,而父类的实例属性则成为了子类原型的属性。
// 父类:function SuperType;子类:function SubType;
SubType.prototype = new SuperType(); // SubType 继承 SuperType
// 根据上一节原型链讲到的知识点:实例化对象的__proto__等于构造函数的prototype
SubType.prototype.__proto__ === SuperType.prototype // true
上述继承关系的结构如下图所示:

从内部实现机制来看,ES5 的继承实质上是先创建子类的实例对象 this,随后再将父类的方法添加到这个 this 对象上。这一过程类似于使用 Father.apply(this) 的方式来实现方法绑定。
ES6 class 继承
ES6 通过 class 关键字结合 extends 和 super 来实现继承。子类自身没有自己的 this 对象,因此必须在 constructor 构造函数中通过调用 super 来继承父类的 this 对象,之后才能对该 this 对象添加子类特有的方法和属性。super 关键字在构造函数中代表父类的构造函数,用于新建父类的 this 对象。在内部实现机制上,ES6 的继承方式与 ES5 截然不同:它实质上是先创建父类的实例对象 this(这需要提前调用 super 方法),然后再使用子类的构造函数来修改 this 指针。
super 用法
super 关键字既可以作为函数使用,也可以作为对象使用。当作为函数使用时,它只能在子类的构造函数中调用,表示父类的构造函数。值得注意的是,此时 super 内部的 this 指向的是子类的实例,因此在子类中调用 super() 等价于 Father.prototype.constructor.call(this)。当作为对象使用时,super 表示父类的原型对象,即等同于 Father.prototype。
二者区别
ES5 与 ES6 的继承并非完全相同,主要存在以下几个差异点:
- 语法写法不同。ES6 的继承通过 extends 关键字以及 super 函数和方法来实现(关于 super 实现继承的具体使用方式,此处不再展开)。
- 定义在类内部的方法均为不可枚举属性,这与 ES5 的行为不同。
- 类定义不存在变量提升现象,这一点与 ES5 完全不同。
- 类相当于其实例的原型,因此在类中定义的所有方法都会被实例继承。如果在方法前加上 static 关键字,则表示该方法不会被实例继承,而是直接通过类名调用,这被称为静态方法。
- 内部实现机制存在显著差异。
ES5 prototype 继承内部实现方式
ES5 的继承机制实质上是先创建子类的实例对象 this,然后再将父类的方法添加到子类(this)上,其操作类似于 Father.apply(this)。

ES6 class 继承内部实现方式
ES6 的继承机制与 ES5 完全不同,其实质是先创建父类的实例对象 this(前提是通过 super 函数调用),并将父类的属性和方法放置到 this 上,然后再使用子类的构造函数来修改 this 指针。

由于实现机制的不同,这两种继承方式在继承原生构造函数时表现出显著差异:
ES5 的写法无法继承原生构造函数(例如 Array、Number 等)。这是因为 ES5 的继承是先创建子类的实例对象 this,再将父类原型的属性和方法重写到子类上。由于无法访问父类的内部属性,导致 ES5 的继承方式无法继承原生构造函数。相比之下,ES6 允许继承构造函数并生成子类。因为 ES6 是先创建父类的实例对象 this,然后再用子类的构造函数进行修饰,所以子类可以继承父类的所有属性和方法。因此,class 可以继承并自定义原生构造函数的子类。extends 不仅可用于继承类,还能用于继承原生构造函数,从而在原生数据结构的基础上构造自定义的数据结构。
扩展
关于内部实现机制的详细说明,可参考《阮一峰的 es6 文档-class 的继承》相关章节。
到此这篇关于 JS 中 ES6 继承和 ES5 继承之间的差别的文章就介绍到这了,更多相关 ES6 继承和 ES5 继承的差别内容请搜索本站以前的文章或继续浏览下面的相关文章,希望大家以后多多支持本站!