如何在 JavaScript 中实现继承?
讲解了 JavaScript 中多种不同的继承方法及其优缺点,包括原型链、借用构造函数、组合继承和 ES6 类继承。
JavaScript实现继承的核心目的是共享和利用其他对象的属性和方法,提高代码复用性。以下是常见的继承方法,以面试者角度从基础方法到现代实现讲述,各方法均附有代码示例及其核心优缺点分析。
- 原型链继承 (Prototype Chain Inheritance)
- 原理:将父类实例作为子类的原型对象(
Child.prototype = new Parent()
),让子类实例继承原型的链关系。 - 优点:实现简单;能自动继承父类新增的原型属性和方法。
- 缺点:引用类型属性在所有实例中共享(一修改全都变化);无法向父类构造函数传参。
function Parent() { this.colors = ['red', 'blue', 'green']; } Parent.prototype.getName = function() { return 'Parent'; }; function Child() {} Child.prototype = new Parent(); const child1 = new Child(); child1.colors.push('black'); //所有实例受影响
- 原理:将父类实例作为子类的原型对象(
- 借用构造函数继承 (Constructor Borrowing, using call/apply)
- 原理:在子类构造函数中调用父类构造函数,复制实例属性(
Parent.call(this)
)。 - 优点:可以传递参数给父类;解决了引用属性共享问题。
- 缺点:只能继承实例属性无法继承原型方法;每个子实例都有独立方法副本浪费内存。
function Parent(name) { this.name = name; } Parent.prototype.sayHello = function() { console.log(this.name); }; function Child(name) { Parent.call(this, name); //借用到属性 } const child1 = new Child('Tom'); // child1.sayHello() Error,未继承原型方法
- 原理:在子类构造函数中调用父类构造函数,复制实例属性(
- 组合继承 (Combined Inheritance)
- 原理:结合使用原型链和借用构造函数:前者用于继承原型方法,后者用于继承实例属性。
- 优点:解决了继承原生原型方法问题,支持传参。
- 缺点:父类构造函数被调用两次,性能稍差;内存浪费因额外调用父类构造。
function Parent(name) { this.name = name; } Parent.prototype.sayHello = function() { console.log(this.name); }; function Child(name) { Parent.call(this, name); //借用属性 } Child.prototype = new Parent(); //继承原型 Child.prototype.constructor = Child; const child1 = new Child('Lucy'); child1.sayHello(); //正确输出Lucy
- ES6类继承 (ES6 Class Extends)
- 原理:使用现代语法
class
和extends
,内部机制优化实现继承,是最推荐的方式。 - 优点:简洁直观、原生支持、完美继承构造函数和原型属性;语法标准度高易于维护。
- 缺点:兼容旧浏览需借助工具编译(如Babel实现代码支持)。
class Parent { constructor(name) { this.name = name; } sayHello() { console.log('Hello ' + this.name); } } class Child extends Parent { constructor(name) { super(name); //调用父类构造 } } const child1 = new Child('Jim'); child1.sayHello(); //输出Hello Jim
- 原理:使用现代语法
面试中优先推荐组合继承(旧兼容环境中)或ES6类继承(modern项目),后两种体现JS本质与现代工程范式更优选择。
注意点优化寄生组合继承可降低内存开销但代码复杂,暂未列出因新手易混淆。