5月28日 03:29

ES6 类继承中 super 关键字的作用是什么?

super 在 ES6 类继承中有两种用法:作为函数调用作为对象引用。核心要点是——super() 调用父类构造函数,super.method() 调用父类原型方法,super.staticMethod() 在静态方法中调用父类静态方法。

super() 作为函数调用

在子类 constructor 中,super() 调用父类构造函数。ES6 的继承机制规定:父类负责创建 this 对象,子类负责在此基础上添加属性。因此 super() 必须在 this 之前调用,否则会抛出 ReferenceError

javascript
class Parent { constructor(name) { this.name = name; } } class Child extends Parent { constructor(name, age) { super(name); // 必须先调 super,否则下面用 this 会报错 this.age = age; } }

如果子类没有显式定义 constructor,引擎会自动插入一个默认的 constructor(...args) { super(...args); }

super.method() 作为对象引用

在子类普通方法中,super 指向父类的 prototype,可以调用父类原型上的方法:

javascript
class Parent { greet() { return 'hello from Parent'; } } class Child extends Parent { greet() { return super.greet() + ' and Child'; } } new Child().greet(); // "hello from Parent and Child"

静态方法中的 super

在子类静态方法中,super 指向父类本身(而非 prototype),因此可以调用父类的静态方法:

javascript
class Parent { static create() { return new this(); } } class Child extends Parent { static create() { return super.create(); // 调用 Parent.create() } }

super 的内部指向总结

使用场景super 指向
super() 在 constructor 中父类构造函数
super.method() 在普通方法中Parent.prototype
super.method() 在静态方法中父类本身(Parent
super.x = value触发父类原型上的 setter(如果有)

追问:子类 constructor 为什么必须先调 super?

ES6 类的继承与 ES5 的寄生组合继承有本质区别。ES5 中是先创建 this(子类自己的对象),再用 Parent.apply(this) 借用父类构造函数挂属性。ES6 反过来了——由父类构造函数先创建并初始化 this,子类再修改。这个顺序由 new.target 控制:当 new Child() 执行时,new.targetChild,但 this 的创建权在 Parent 那里。super() 执行后 this 才可用。

追问:super.x = value 有什么陷阱?

super 的属性赋值时,并不会像直觉那样去修改父类原型上的属性。实际行为是:如果父类原型上定义了该属性的 setter,赋值操作会触发那个 setterthis 指向当前子类实例;如果没有 setter,则相当于直接在 this 上创建属性:

javascript
class Parent { set x(val) { console.log('setter called with', val); } } class Child extends Parent { setX() { super.x = 42; // 触发 Parent.prototype 的 setter } } new Child().setX(); // "setter called with 42"

追问:ES6 继承与 ES5 原型继承的区别

ES5 寄生组合继承ES6 class 继承
this 创建子类先创建 this,再借用父类父类构造函数创建 this
super无,用 Parent.call(this)super() 必须
原型链手动 Object.create(Parent.prototype)extends 自动建立
静态方法不会继承自动继承
new.target不存在控制实例化行为
标签:前端ES6