深入解析JavaScript继承机制:从原型到寄生组合式

作者:青柠

时间:2026-10-30

浏览:511

本文详细解析JavaScript中的继承实现方式,涵盖原型继承、组合式继承及寄生组合式继承。重点分析各模式的优缺点,如原型共享导致的引用类型问题、构造函数重复调用等,并深入探讨new操作符的执行过程,帮助开发者理解并选择最优继承方案。

文章目录

JavaScript原型继承基础

在JavaScript中,开发者可以利用原型机制来实现对象间的继承关系。

具体示例如下所示:


function baz(){
this.oo="";
}

function foo(){

}
foo.prototype=new baz();
var myFoo=new foo();
myFoo.oo;

通过上述代码,我们可以访问到baz对象中的oo属性。然而在实际开发中,这种简单的原型继承方式存在缺陷,因为原型具有共享特性,其数据存储在堆内存中。

当所有实例共享同一个原型时,如果baz的属性包含引用类型数据,就会引发问题。一旦某个实例修改了该引用属性,其他实例也会随之改变,导致数据混乱。

组合式继承的局限

为了解决这一问题,组合式继承应运而生。


function baz(){
this.oo="";
}
baz.prototype.xx=function(){

}

function foo(){
baz.call(this);//第二次调用
}
foo.prototype=new baz();//第一次调用
var myFoo=new foo();
myFoo.oo;
myFoo.xx;

这种方式虽然解决了引用类型共享的问题,但也引入了新的瑕疵:如代码所示,baz构造函数会被调用两次。对于追求代码完美的开发者而言,这种冗余是不可接受的。

需要澄清的是,采用第二种方式并不能避免第一种方式中出现的问题。

这是因为JavaScript的属性查找机制是从对象自身开始,若未找到才会向原型链查找。在call执行时,属性已经被直接继承到实例中。

进一步思考,既然call已经实现了属性继承,是否可以直接使用call继承而忽略原型呢?答案是否定的。作为注重性能的开发者,我们不能放弃原型的优势。

将方法定义在原型上可以实现方法共享,从而显著提升性能。

寄生组合式继承实现

寄生组合式继承是更优的解决方案。


__extends=function (p,c){
function ctor(){
this.constructor=c;//赋值构造函数
}
ctor.prototype=p.prototype;
c.prototype=new ctor();
}

function baz(){
this.oo=[1];
}
baz.prototype.xx=function(){

}
__extends(baz,foo);
function foo(){
baz.call(this);
}
var myFoo=new foo();
myFoo.oo;
myFoo.xx;

该模式不仅解决了构造函数被调用两次的问题,还确保了在对象调用构造函数时,调用的是真实的创建对象的函数,而非原型链上的其他构造函数。

具体代码实现如前文所示。

构造函数是原型对象上的一个属性,负责创建对象。由于我们将原型属性重新赋值,导致构造函数变成了继承而来的属性。

new操作符执行原理

这里需要解释对象的创建过程,即new操作符具体执行了哪些步骤。

以以下代码为例:

var a=new b();

其实际执行过程为:首先创建空对象a,然后执行b.call(a)来初始化a。在call执行之前,还有一步关键操作,即将a的内部原型对象设置为b的原型属性所指向的原型对象。

原型上包含构造函数属性,该构造函数用于创建对象并分配内存空间。

以上就是JavaScript继承机制的主要内容。希望读者能保持平和心态,深入理解并应用这些知识。

感谢阅读,希望对大家理解JavaScript继承有所帮助。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章