深入理解JavaScript继承机制:原型链与模拟实现

作者:拾光时间:2026-10-27 19:33:30浏览:142

本文深入解析JavaScript的继承机制,指出其不同于传统面向对象语言,主要通过原型链(prototype)和构造函数模拟实现。文章通过Person与Programmer、Employee等具体代码示例,详细演示了如何设置原型对象、调用父类方法以及处理属性覆盖与删除,帮助开发者理解JS中继承的本质与局限。

JavaScript继承机制概述

近期阅读到一篇关于淘宝面试经历的文章,其中暴露出我对某些基础概念的认知盲区。为了厘清这些疑惑并巩固知识,我决定专门撰写此文,深入梳理相关知识点。

文中探讨的核心问题是:JavaScript究竟是如何实现继承的?本文将整理并解析网络上常见的几种实现方案及实例,旨在通过具体案例加深理解。

在JavaScript中,函数(function)扮演着极其重要的角色。它不仅用于定义普通函数,还可以被用作类的构造函数来定义类。

JavaScript的继承机制颇具特色,与传统面向对象语言(如C++)不同。它没有public、private等访问控制修饰符,也不使用implement等特定关键字来标识继承关系。

以下通过一个具体示例,展示JavaScript中类的继承实现方式。

代码如下:

<script type="text/javascript">
function Person() {
// 属性
this.Gender = "female";
this.Age = 18;
this.Words = "Silence";
// 方法
this.shouting = function() {
alert("开心哦!父类的方法");
    }
}
// 继承
function Programmer() {
this.base = Person;
}
Programmer.prototype = new Person;
// 为子类添加新的方法
Programmer.prototype.typeCode = function() {
alert("俺是敲代码的!IT民工,很不开心。子类的方法");
}
// 调用示例
function sayHello() {
var a = new Programmer();
alert(a.Gender); // 调用父类的属性
a.shouting(); // 调用父类的方法
a.typeCode(); // 调用子类的方法
}        
sayHello();
</script>

在上述示例中,首先定义了一个包含属性和方法的Person类。接着定义Programmer类,其中base属性虽非必需,但出于规范及后续追踪继承关系的考虑通常会保留。关键在于将Person的实例赋值给Programmer的原型对象(prototype),从而实现了类的继承。

原型链与构造函数原理

模拟JavaScript中类和继承的一些原理

在传统面向对象语言中,我们使用类来创建自定义对象。然而JavaScript中万物皆对象,那么如何创建自定义对象呢?

这引入了原型(prototype)的概念。我们可以将prototype视为一个模板,新创建的自定义对象都是该模板的一个拷贝(实际上并非拷贝,而是指向该模板的隐藏链接,这种链接对用户不可见,因此给人造成拷贝的错觉)。

以下示例展示了如何通过prototype创建自定义对象:

代码如下:

// 构造函数
function Person(name, sex) {
this.name = name;
this.sex = sex;
  }
// 定义Person的原型,原型中的属性可以被自定义对象引用
Person.prototype = {
getName: function() {
return this.name;
      },
getSex: function() {
return this.sex;
      }
  }

这里将函数Person称为构造函数,即用于创建自定义对象的函数。可以看出,JavaScript通过构造函数结合原型的方式,模拟实现了类的功能。

下面通过具体例子阐述创建自定义对象时JavaScript内部执行的具体步骤:

代码如下:

var zhang = new Person("ZhangSan", "man");
console.log(zhang.getName()); // "ZhangSan"
var chun = new Person("ChunHua", "woman");
console.log(chun.getName()); // "ChunHua"

当执行var zhang = new Person("ZhangSan", "man")时,内部依次执行以下操作:

1. 创建一个空白对象(new Object())。 2. 将Person.prototype中的属性(键值对)拷贝到这个空对象中(内部实现实为隐藏链接,但表现为类似拷贝的效果)。 3. 将该对象通过this关键字传递给构造函数并执行。 4. 将该对象赋值给变量zhang。 所有步骤完成后,对象创建完毕。 为了证明prototype模板并非被拷贝到实例中,而是通过链接方式存在,请参考以下代码:

代码如下:

function Person(name, sex) {
this.name = name;
this.sex = sex;
}
Person.prototype.age = 20;
var zhang = new Person("ZhangSan", "man");
console.log(zhang.age); // 20
// 覆盖prototype中的age属性
zhang.age = 19;
console.log(zhang.age); // 19
delete zhang.age;
// 在删除实例属性age后,此属性值又从prototype中获取
console.log(zhang.age); // 20

在上述示例中,如果是通过拷贝实现的,删除age属性后对象内应不再存在该属性。但示例中删除实例属性后仍能输出父级值,说明仅删除了子类同名属性,而父类中的age属性通过不可见的链接依然存在于对象中。

简单继承的实现示例

如何在JavaScript中实现简单的继承?

以下示例创建一个Employee类,它从Person继承了原型(prototype)中的所有属性。

代码如下:

function Employee(name, sex, employeeID) {
this.name = name;
this.sex = sex;
this.employeeID = employeeID;
}
// 将Employee的原型指向Person的一个实例
// 因为Person的实例可以调用Person原型中的方法, 所以Employee的实例也可以调用Person原型中的所有属性。
Employee.prototype = new Person();
Employee.prototype.getEmployeeID = function() {
return this.employeeID;
};
var zhang = new Employee("ZhangSan", "man", "1234");
console.log(zhang.getName()); // "ZhangSan

以上展示了JavaScript实现继承的具体过程及常用方法。

总结而言,JavaScript的继承机制是通过模拟实现的,相较于传统面向对象语言显得较为粗糙且存在一定缺陷,但这并未降低前端开发者在此领域的探索热情。

作者最新文章