掌握 JavaScript 面向对象编程的核心代码:深入分析 JavaScript 面向对象机制的对象基础、原型模式和继承策略全面指导高效创建高质量、可维护的代码 - V. 继承机制
最编程
2024-05-01 21:44:56
...
ECMAScript(JavaScript)提供了多种继承策略,每种策略都有其特点和适用场景。以下是几种主要的继承方式的详解与示例:
1. 原型链继承
原理:通过让子类型的原型对象等于父类型的实例,使得子类型能够访问到父类型上的属性和方法。
示例:
function SuperType() {
this.superProperty = true;
}
SuperType.prototype.getSuperValue = function() {
return this.superProperty;
};
function SubType() {
this.subProperty = false;
}
// 继承SuperType
SubType.prototype = new SuperType();
// 修复构造函数引用
SubType.prototype.constructor = SubType;
SubType.prototype.getSubValue = function() {
return this.subProperty;
};
var instance = new SubType();
console.log(instance.getSuperValue()); // 输出: true
2. 构造函数继承(借用构造函数)
原理:在子类型构造函数内部通过call
或apply
方法调用父类型构造函数,为子类型实例添加属性。
示例:
function SuperType(name) {
this.name = name;
}
function SubType(name, age) {
SuperType.call(this, name); // 借用构造函数
this.age = age;
}
var instance = new SubType("Tom", 25);
console.log(instance.name); // 输出: Tom
console.log(instance.age); // 输出: 25
3. 组合继承(原型链+构造函数继承)
原理:结合原型链继承和构造函数继承的优点,既可以在子类型中继承父类型的属性和方法,又能保持每个实例的唯一性。
示例:
function SuperType(name) {
this.name = name;
}
SuperType.prototype.sayName = function() {
console.log(this.name);
};
function SubType(name, age) {
SuperType.call(this, name); // 继承属性
this.age = age;
}
// 继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType; // 修复构造函数引用
SubType.prototype.sayAge = function() {
console.log(this.age);
};
var instance = new SubType("Tom", 25);
instance.sayName(); // 输出: Tom
instance.sayAge(); // 输出: 25
4. 寄生式继承
原理:创建一个对象作为父类型的实例,然后为其添加额外的属性和方法,最后返回这个对象。
示例:
function createAnother(original) {
var clone = Object.create(original); // 或者使用 Object.assign({}, original) 进行浅拷贝
clone.extraMethod = function() {
console.log("Extra method");
};
return clone;
}
var original = { value: 1 };
var another = createAnother(original);
another.extraMethod(); // 输出: Extra method
5. 寄生组合式继承
原理:结合了寄生式继承和组合继承的特点,优化了组合继承中重复调用父构造函数的问题。
示例:
function inheritPrototype(subType, superType) {
var prototype = Object.create(superType.prototype); // 创建父类型的原型副本
prototype.constructor = subType; // 修正构造函数的指向
subType.prototype = prototype; // 将子类型的原型指向新创建的原型副本
}
function SuperType(name) {
this.name = name;
}
SuperType.prototype.sayName = function() {
console.log(this.name);
};
function SubType(name, age) {
SuperType.call(this, name); // 继承属性
this.age = age;
}
inheritPrototype(SubType, SuperType); // 实现继承
SubType.prototype.sayAge = function() {
console.log(this.age);
};
var instance = new SubType("Tom", 25);
instance.sayName(); // 输出: Tom
instance.sayAge(); // 输出: 25
6. ES6 Class继承
原理:ES6引入了class
关键字,使得继承更加简洁明了,背后仍然是基于原型继承机制。
示例:
class SuperType {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}
class SubType extends SuperType {
constructor(name, age) {
super(name); // 调用父类构造函数
this.age = age;
}
sayAge() {
console.log(this.age);
}
}
let instance = new SubType("Tom", 25);
instance.sayName(); // 输出: Tom
instance.sayAge(); // 输出: 25
每种继承策略各有千秋,开发者应根据实际需求选择最适合的继承方式。ES6的class
继承因其简洁易读性,逐渐成为主流选择。
在ECMAScript中运用面向对象技术,关键在于合理设计类与接口,利用ES6的class语法简化继承和封装过程。采用组合而非深度继承提高灵活性,利用 Mixins 引入多重继承特性。重视模块化,合理划分职责,利用闭包和模块模式增强封装性。适时采用原型链继承与构造函数继承,结合实际情况灵活选择,确保代码既高效又易于理解维护。