本文深入解析 JavaScript 中的几种核心继承模式。首先介绍结合原型链与构造函数优点的组合继承,指出其父类构造函数调用两次的效率问题。随后讲解寄生式继承原理,最终引出高效的寄生式组合继承方案,通过 inheritPrototype 函数优化原型链,避免不必要的属性复制,是前端开发中推荐的继承实现方式。
组合继承
组合继承,亦称伪经典继承,融合了原型链与盗用构造函数两种技术的优势。其核心思路是利用原型链来继承定义在原型上的属性和方法,同时通过盗用构造函数来继承实例属性。这种设计既实现了方法的复用,又确保了每个实例拥有独立的属性副本。
function SuperType (name) {
this.name = name;
this.colors = ["red","yellow","bule"];
}
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.sayAge = function(){
console.log(this.age);
}
let instancel = new SubType("jackson",22);
instancel.colors.push("pink");
instancel.sayName(); // "jackson"
instancel.sayAge();//22
console.log(instancel.colors);// ["red", "yellow", "bule", "pink"]
let instance2 = new SubType("bear", 20);
console.log(instance2.colors); // ["red", "yellow", "bule"]
instance2.sayName(); // "bear";
instance2.sayAge(); // 20
观察上述代码逻辑,SubType 通过调用 SuperType 并传入 name 参数,进而定义自身的属性 age,同时将 SubType.prototype 赋值为 SuperType 的实例。在原型赋值完成后,再向该原型添加 sayage 方法。此时创建的两个 SubType 实例不仅拥有各自的属性,还能共享相同的方法,逻辑清晰直观。
组合继承有效弥补了原型链和盗用构造函数各自的局限性,是目前 JavaScript 中最广泛使用的继承模式。
寄生式继承
寄生式继承的核心在于使用一个函数来包装对象,并返回该函数的调用结果。这个函数因此具备了为实例或对象动态添加属性的能力。Object.create() 方法的实现原理正是基于此。
// 寄生式继承
function subobject(obj) {
let clone = Object(obj);
clone.sayName = function(){
console.log("jackson")
};
return clone;
}
let sub = {
name:"bear"
}
let sup = subobject(sub);
sup.sayName();//jackson
该示例基于 sub 对象返回一个新的 sup 对象。返回的 sup 对象不仅继承了 sub 的属性和方法,还额外增加了一个 sayName() 新方法。
寄生式继承同样适用于主要关注对象本身而非类型或构造函数的场景。值得注意的是,Object() 函数并非寄生式继承的必要条件,任何能够返回新对象的函数均可在此场景下使用。
需要注意的是,通过寄生式继承给对象添加函数会导致函数难以复用,这一点与构造函数模式类似。
寄生式组合继承
传统的组合继承存在效率缺陷,因为父类构造函数会被调用两次:一次是在创建子类原型时,另一次是在子类构造函数内部执行时。从本质上看,子类只需在执行时重写自己的原型即可,无需重复调用父类构造函数。
function inheritPrototype(subType, superType) {
let prototype = Object(superType.prototype); // 创建对象
prototype.constructor = subType; // 增强对象
subType.prototype = prototype; // 赋值对象
}
inheritPrototype() 函数实现了寄生式组合继承的核心逻辑。该函数接收两个参数:子类构造函数和父类构造函数。函数内部首先创建父类原型的副本,接着为返回的 prototype 对象设置 constructor 属性,以解决因重写原型而导致的默认 constructor 丢失问题。最后,将新创建的对象赋值给子类型的原型。调用 inheritPrototype() 即可实现前述例子中的子类型原型赋值操作。
function SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
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);
};
在此方案中,SuperType 构造函数仅被调用一次,从而避免了在 SubType.prototype 上产生不必要且未被使用的属性。因此,该例子的执行效率更高,同时原型链结构保持不变。
总结
至此,关于 JavaScript 寄生式组合继承的介绍已完成。如需了解更多相关 JS 寄生式组合继承内容,建议搜索本站历史文章或继续浏览后续相关文章,感谢大家的支持。