本文深入解析JavaScript中的两种继承模式。首先介绍借用构造函数技术,通过在子类中调用父类构造函数并传递参数,解决原型中包含引用类型值导致的问题,确保每个实例拥有独立属性副本。接着阐述组合式继承,结合原型链与借用构造函数,既实现方法复用又保证实例属性独立,是经典且高效的继承方案。
借用构造函数技术
2. 借用构造函数
针对原型链中引用类型值共享引发的问题,开发者采用了一种名为借用构造函数(constructor stealing)的技术,该技术也被称为伪造对象或经典继承。
其核心逻辑是在子类的构造函数内部,显式调用超类型的构造函数。
借助 apply() 和 call() 方法,可以在新创建的子类对象上下文中执行超类型的构造函数逻辑。
function SuperType(){
this.colors = ["red", "blue", "green"];
}
function SubType(){
//继承了 SuperType
SuperType.apply(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //red,blue,green,black
var instance2 = new SubType();
alert(instance2.colors); //red,blue,green
以具体示例来看,在创建 SubType 实例(如 instance1 和 instance2)时,实际上是在该实例的作用域内调用了 SuperType 构造函数。这使得 SuperType 中定义的所有对象初始化代码得以在新 SubType 对象上执行,从而确保每个 SubType 实例都拥有自己独立的 colors 属性副本。
传递参数
相较于单纯的原型链继承,借用构造函数的一个显著优势在于,它允许子类构造函数向超类型构造函数传递参数。
function SuperType(name){
this.name = name;
}
function SubType(){
SuperType.call(this, "Bob");
this.age = 18;
}
var instance1 = new SubType();
alert(instance1.age); //18
alert(instance1.name); //Bob
然而,借用构造函数也存在局限性:
由于所有方法均在构造函数内部定义,导致函数无法复用。此外,超类型原型中定义的方法对子类型而言不可见,无法实现方法共享。
组合式继承方案
3. 组合式继承
组合式继承(combination inheritance),亦称伪经典继承,旨在将原型链与借用构造函数两种技术结合,从而发挥各自优势。
利用原型链来继承原型上的属性和方法;
通过借用构造函数来实现对实例属性的继承。
这种模式既通过在原型上定义方法实现了函数的复用,又确保每个实例都拥有自己的属性副本。
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
}
function SubType(name, age){
//继承属性
SuperType.call(this, name);
this.age = age;
}
//继承方法
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function(){
alert(this.age);
}
var instance1 = new SubType("Bob", 22);
instance1.colors.push("black");
alert(instance1.colors); //red,blue,green,black
instance1.sayName(); //Bob
instance1.sayAge(); //22
var instance2 = new SubType("Alice", 21);
alert(instance2.colors); //red,blue,green
instance2.sayName(); //Alice
instance2.sayAge(); //21
在示例中,SuperType 构造函数定义了两个属性:name 和 colors,并在其原型上定义了一个方法 sayName()。
SubType 构造函数在调用 SuperType 构造函数时传入了 name 参数,并定义了自身属性 age。随后,将 SuperType 的实例赋值给 SubType 的原型,并在该原型上定义了方法 sayAge()。
通过这种方式,两个不同的 SubType 实例既能分别拥有自己的属性(包括 colors 属性),又能共享相同的方法。
以上关于 JS 继承中借用构造函数与组合式继承的探讨到此结束,希望能为读者提供有价值的参考。