ES5 与 ES6 继承的区别(除写法外)
1. 继承机制不同
- ES5 的继承:实质上是先创建子类的实例对象
this,然后再将父类的方法添加到this上(通过Parent.call(this))。 - ES6 的继承:实质上是先创建父类的实例对象
this(所以必须先调用父类的super()方法),然后再用子类的构造函数修改this。
2. this 与 super
ES6 通过 class 关键字定义类,里面有构造方法,类之间通过 extends 关键字实现继承。子类必须在 constructor 方法中调用 super 方法,否则新建实例会报错。因为子类没有自己的 this 对象,而是继承了父类的 this 对象,然后对其进行加工;如果不调用 super,子类就拿不到 this 对象。
super关键字指代父类的实例(即父类的this对象)。在子类构造函数中,调用super后才可使用this关键字,否则报错。
3. 对比示例
// ES5 寄生组合式继承
function Parent(name) { this.name = name; }
Parent.prototype.say = function () { console.log(this.name); };
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
// ES6 class extends
class Parent {
constructor(name) { this.name = name; }
say() { console.log(this.name); }
}
class Child extends Parent {
constructor(name, age) {
super(name);
this.age = age;
}
}
4. ES6 class 自身的特性差异
除继承机制外,ES6 class 相比 ES5 构造函数还有以下语义差异:
4.1 不提升、暂时性死区
class 声明会提升,但不会初始化赋值,进入暂时性死区(TDZ),行为类似 let / const。
4.2 默认严格模式
class 声明内部会自动启用严格模式。
4.3 所有方法不可枚举
class 的所有方法(包括静态方法和实例方法)都是不可枚举的;而 ES5 中挂在 prototype 上的方法默认是可枚举的。
function Bar() {
this.bar = 42;
}
Bar.answer = function() {
return 42;
};
Bar.prototype.print = function() {
console.log(this.bar);
};
const barKeys = Object.keys(Bar); // ['answer']
const barProtoKeys = Object.keys(Bar.prototype); // ['print']
class Foo {
constructor() {
this.foo = 42;
}
static answer() {
return 42;
}
print() {
console.log(this.foo);
}
}
const fooKeys = Object.keys(Foo); // []
const fooProtoKeys = Object.keys(Foo.prototype); // []
4.4 方法没有原型对象 prototype
class 的所有方法都没有原型对象 prototype,所以也没有 [[construct]],不能使用 new 来调用。
function Bar() {
this.bar = 42;
}
const bar = Bar(); // it's ok
class Foo {
constructor() {
this.foo = 42;
}
}
const foo = Foo();
// TypeError: Class constructor Foo cannot be invoked without 'new'
4.5 不能在内部重写类名
class 内部无法重写类名(构造函数中 ClassName = ... 会抛 TypeError: Assignment to constant variable);函数则可以。
function Bar() {
Bar = "Baz"; // it's ok
this.bar = 42;
}
const bar = new Bar();
// Bar: 'Baz'
// bar: Bar {bar: 42}
class Foo {
constructor() {
this.foo = 42;
Foo = "Fol"; // TypeError: Assignment to constant variable
}
}
const foo = new Foo();
Foo = "Fol"; // it's ok(外部仍可改写)
5. 其他细节差异
- ES6
class是 ES5 继承的语法糖,底层仍是原型链,但写法更清晰。 - ES6 继承通过
Object.setPrototypeOf把子类原型链指向父类,避免了 ES5 中多次调用父类构造的问题。 - ES6
class内定义的方法不可枚举(与 ES5 不同),更符合类的语义。 - ES6 支持静态方法的继承(
static关键字)。
来源整理自:vue3js.cn 面试官系列



