JavaScript 继承机制详解:对象冒充与原型链

作者:纸飞机

时间:2026-10-28

浏览:439

本文深入解析 JavaScript 的两种核心继承机制:对象冒充与原型链。对象冒充通过临时属性或 call/apply 方法实现,但存在内存浪费且无法继承原型属性。原型链利用 __proto__ 链接解决共享问题,却难以在实例化时向父类传参。文章最后推荐结合两者优势的混合继承模式,并详细演示代码实现与注意事项。

文章目录

JavaScript 继承机制概述

在 JavaScript 中,实现继承主要依赖两种机制:对象冒充(Object Masquerading)和原型链(Prototype Chain)。

对象冒充实现与缺陷

一、对象冒充实现方式 对象冒充主要包含三种具体实现路径:临时属性法、call() 方法以及 apply() 方法。

代码示例如下:

function Person(name){
this.name = name;
this.say = function(){
alert('My name is '+this.name);
     }
}
function F2E(name,id){
this.temp = Person;
this.temp(name);
delete this.temp;
this.id = id;
this.showId = function(){
alert('Good morning,Sir,My work number is '+this.id);
     }
}
var simon = new F2E('Simon',9527);
simon.say();
simon.showId();

2. call()/apply() 方式


这种方式的本质在于改变函数内部 this 指针的指向对象。


代码示例如下:

function Person(name){
this.name = name;
this.say = function(){
alert('My name is '+this.name);
     }
}
function F2E(name,id){
Person.call(this,name); //apply()方式改成Person.apply(this,new Array(name));
this.id = id;
this.showId = function(){
alert('Good morning,Sir,My work number is '+this.id);
     }
}
var simon = new F2E('Simon',9527);
simon.say();
simon.showId();

缺点分析:首先观察内存分配情况:

JavaScript 继承机制详解:对象冒充与原型链 配图

在面向对象概念中,执行 new 实例化后,对象会在堆内存中开辟独立空间。需要注意的是,成员方法定义在代码段中,且理论上方法是共用的。然而,通过对象冒充方式继承时,所有成员方法都直接指向 this 实例。这意味着每次 new 操作后,每个实例都会创建一份独立的方法副本,而非共用,从而导致严重的内存浪费。此外,对象冒充无法继承通过 prototype 定义的变量和方法。如下代码执行时会报错:

代码示例如下:

function Person(name){
this.name = name;
this.say = function(){
alert('My name is '+this.name);
     }
}
Person.prototype.age = 20;
Person.prototype.sayAge = function(){alert('My age is '+this.age)};
function F2E(name,id){
Person.apply(this,new Array(name));
this.id = id;
this.showId = function(){
alert('Good morning,Sir,My work number is '+this.id);
     }
}
var simon = new F2E('Simon',9527);
simon.sayAge(); //提示TypeError: simon.sayAge is not a function

二、原型链方式

原型链原理与局限性

代码示例如下:

function Person(){
this.name = 'Simon';
}
Person.prototype.say = function(){
alert('My name is '+this.name);
}
function F2E(id){
this.id = id;
this.showId = function(){
alert('Good morning,Sir,My work number is '+this.id);
     }
}
F2E.prototype = new Person();
var simon = new F2E(9527);
simon.say();
simon.showId();
alert(simon.hasOwnProperty('id')); //检查是否为自身属性

接下来结合上述示例深入理解 JS 原型链概念:

JavaScript 继承机制详解:对象冒充与原型链 配图

原型链可理解为:JS 中每个对象均包含一个隐藏的 __proto__ 属性。实例化对象的 __proto__ 指向其所属类的 prototype 属性;若该 prototype 被赋值为另一个实例化对象,则该新对象的 __proto__ 又指向其类的 prototype,如此循环形成一条链。这正是前文代码中

代码示例如下:

F2E.prototype = new Person()

这句关键语句的作用。当 JS 对象访问某个属性时,会先查找自身属性,若未找到则沿原型链依次向上查找。由于原型链上的方法是共用的,因此解决了对象冒充导致的内存浪费问题。

下面分析其缺点: 缺点同样明显:采用原型链方式继承时,实例化子类时无法向父类传递参数。这也是为何前例中 function Person() 没有参数,而是直接硬编码 this.name='Simon' 的原因。以下代码无法达到预期效果:

代码示例如下:

function Person(name){
this.name = name;
}
Person.prototype.say = function(){
alert('My name is '+this.name);
}
function F2E(name,id){
this.id = id;
this.showId = function(){
alert('Good morning,Sir,My work number is '+this.id);
     }
}
F2E.prototype = new Person();
var simon = new F2E("Simon",9527);
simon.say();
simon.showId();
 
function Person(name){
this.name = name;
}
Person.prototype.say = function(){
alert('My name is '+this.name);
}
function F2E(name,id){
this.id = id;
this.showId = function(){
alert('Good morning,Sir,My work number is '+this.id);
     }
}
F2E.prototype = new Person(); //此处无法进行传值,this.name或者name都不行,直接写F2E.prototype = new Person('wood')是可以的,但是这样的话simon.say()就变成了My name is wood
var simon = new F2E("Simon",9527);
simon.say(); //弹出 My name is undefined
simon.showId();

混合继承模式推荐

最后,总结一种较为理想的继承实现方式:成员变量采用对象冒充,成员方法采用原型链。代码示例如下:

代码示例如下:

function Person(name){
this.name = name;
}
Person.prototype.say = function(){
alert('My name is '+this.name);
}
function F2E(name,id){
Person.call(this,name);
this.id = id;
}
F2E.prototype = new Person();
//此处注意一个细节,showId不能写在F2E.prototype = new Person();前面
F2E.prototype.showId = function(){
alert('Good morning,Sir,My work number is '+this.id);
}
var simon = new F2E("Simon",9527);
simon.say();
simon.showId();

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章