JavaScript 继承的实现方式有哪些?
JavaScript 提供多种继承方式,如原型链和组合继承,用于对象创建和方法传递。
JavaScript 提供多种继承实现方式,基于原型机制,每种方式有不同原理和应用场景。以下是常见方法的解释:
- 原型链继承
通过将子类的原型设置为父类实例实现继承。- 原理:子类实例可访问父类原型上的属性和方法。
- 示例代码:
function Parent() { this.name = 'Parent'; } Parent.prototype.sayName = function() { console.log(this.name); }; function Child() {} // 设置子类原型为父类实例 Child.prototype = new Parent(); const child = new Child(); child.sayName(); // 输出 'Parent'
- 优势:简单易懂。
- 劣势:所有实例共享父类引用属性;无法传递参数给父构造函数。
- 借用构造函数继承
在子类构造函数中调用父类构造函数,实现属性和方法的复制。- 原理:使用
call
或apply
将父类的this
绑定到子类实例。 - 示例代码:
function Parent(name) { this.name = name; } function Child(name, age) { Parent.call(this, name); // 借用父类构造函数 this.age = age; } const child = new Child('Tom', 18); console.log(child.name); // 输出 'Tom'
- 优势:解决属性共享问题,可传递参数。
- 劣势:无法继承父类原型上的方法。
- 原理:使用
- 组合继承
结合原型链和借用构造函数的优点,是目前推荐的方式。- 原理:用借用构造处理属性,原型链处理原型方法。
- 示例代码:
function Parent(name) { this.name = name; } Parent.prototype.sayName = function() { console.log(this.name); }; function Child(name, age) { Parent.call(this, name); // 处理属性 this.age = age; } Child.prototype = new Parent(); // 处理原型方法 const child = new Child('Alice', 10); child.sayName(); // 输出 'Alice'
- 优势:属性独立,方法可共享。
- 劣势:需两次调用父构造函数。
- 原型式继承
使用对象直接基于一个原类型对象创建新实例。- 原理:通过自定义函数创建对象,将传入的对象作为新对象的原型。
- 示例代码:
const parent = { name: 'parent', sayHello: function() { console.log('Hello from ' + this.name); } }; const child = Object.create(parent); child.name = 'child'; child.sayHello(); // 输出 'Hello from child'
- 优势:轻量级实现继承。
- 劣势:属性和方法可被覆盖。
- 寄生组合式继承
优化的组合继承方式,避免重复调用父构造函数。- 原理:通过拷贝父类原型继承方法,无需实例化。
- 示例代码:
function inheritPrototype(child, parent) { const proto = Object.create(parent.prototype); proto.constructor = child; child.prototype = proto; } function Parent() { this.name = 'Parent'; } function Child() { Parent.call(this); this.name = 'Child'; } inheritPrototype(Child, Parent); const child = new Child(); console.log(child.name); // 输出 'Child'
- 优势:性能最佳,无冗余调取。
- 劣势:代码稍复杂。
- ES6 类继承
使用extends
关键字简化语法,基于类语法。- 原理:语法糖,编译为原型机制。
- 示例代码:
class Parent { constructor(name) { this.name = name; } sayName() { console.log(this.name); } } class Child extends Parent { constructor(name, age) { super(name); // 调用父类构造函数 this.age = age; } } const child = new Child('Bob', 20); child.sayName(); // 输出 'Bob'
- 优势:现代、简洁、易读。
- 劣势:仅适用于现代 ES6+ 环境。