JavaScript 原型与原型链继承机制详解
本文详细解析 JavaScript 面向对象编程中的原型(prototype)与原型链机制。通过构造函数、原型对象及 constructor 属性的循环引用关系,阐明对象如何继承属性与方法。文章结合代码示例,演示原型链的查找规则、方法重写对实例的影响,以及 Object.prototype 在继承体系中的最终地位,帮助开发者掌握 JS 动态继承的核心逻辑。
JavaScript 原型与原型链继承机制详解
在面向对象编程实践中,对象间的继承关系是不可或缺的基础。而在 JavaScript 中,原型(prototype)是实现这一继承机制的核心手段之一。
首先通过一段代码示例来直观展示这一过程。
代码如下:
function person(name, age) {
this.name = name;
this.age = age;
}
person.prototype.getInfo = function() {
alert("My name is "+this.name+", and I have "+this.age+" years old");
}
var zhangchen = new person("zhangchen", 23);
zhangchen.getInfo(); //output My name is zhangchen, and I have 23 years old; 原型对象与构造函数关系
从运行结果可以看出,使用 new 关键字创建的 zhangchen 对象成功继承了 person 构造函数中通过原型定义的 getInfo() 方法。接下来,我们将深入分析新创建的 zhangchen 对象是如何具体继承 person 对象的属性和方法的。
原型:在 JavaScript 的面向对象编程体系中,原型对象是一个核心概念。JavaScript 中的对象被视为现有示例(即原型)对象的副本而创建,这一命名即源于此概念。原型对象上的任何属性和方法,都会表现为从该原型的构造函数所创建对象的属性和方法。换句话说,这些对象是从其原型中继承了属性和方法。当创建 zhangchen 对象时:
代码如下:
var zhangchen = new company("zhangchen", 23); zhangchen 所引用的对象将从其原型继承属性和方法,该对象的原型来源于构造函数(在此例中为函数 person)的属性。
在 JavaScript 中,每个函数都拥有一个名为 prototype 的属性,用于引用原型对象。与此同时,此原型对象又包含一个名为 constructor 的属性,该属性反过来引用函数本身。这构成了一种循环引用关系,下图更清晰地展示了这种循环关联。

图1 循环关系
现在,当通过 new 运算符使用函数(上述示例中的 person)创建对象时,所得到的对象将继承 person.prototype 的属性。在上图中,可以看到 person.prototype 对象拥有一个回指 person 函数的构造函数属性。因此,每个 person 对象(从 person.prototype 继承而来)都拥有一个回指 person 函数的构造函数属性。
我们可以使用以下代码来验证这种循环关系是否正确:
代码如下:
function person(name, age) {
this.name = name;
this.age = age;
}
person.prototype.getInfo = function() {
alert("My name is "+this.name+", and I have "+this.age+" years old");
}
var zhangchen = new person("zhangchen", 23);
alert(zhangchen.constructor == person.prototype.constructor); //output true
alert(zhangchen.constructor == person);// output true
alert(person.prototype.isPrototypeOf(zhangchen)); //output true上述代码中对 isPrototypeOf() 方法的调用源自何处呢?它并非来自 person.prototype 对象。实际上,在 person.prototype 和 person 实例中还可以调用其他方法,例如 toString、toLocaleString 和 valueOf,但它们均不来自 person.prototype。这些方法实际上源自 JavaScript 中的 Object.prototype,它是所有原型的最终基础原型(Object.prototype 的原型为 null)。
在以上示例中,zhangchen.prototype 是一个对象。它是通过调用 Object 构造函数创建的(尽管这一过程不可见),相当于执行了以下代码:
代码如下:
zhangchen.prototype = new Object(); 因此,正如 person 实例继承 person.prototype 一样,zhangchen.prototype 也继承 Object.prototype。这使得所有 zhangchen 实例同时也继承了 Object.prototype 的方法和属性。
原型链查找机制
原型链:每个 JavaScript 对象都继承一条原型链,且所有原型最终都终止于 Object.prototype。需要注意的是,这种继承是活动对象之间的继承,它不同于常见的在声明类时发生的类间继承概念。因此,JavaScript 的继承具有更强的动态性。它通过一个简单的算法实现这一点:当您尝试访问对象的属性或方法时,JavaScript 会检查该属性或方法是否在该对象中定义。如果未找到,则检查对象的原型;如果仍未找到,则继续检查该对象的原型的原型,以此类推,直到检查到 Object.prototype。下图说明了此解析过程:
图2 toString()方法的解析过程
从上述解析过程可以看出,如果在对象中定义了属性或方法 X,则该对象的原型中将隐藏同名属性或方法。例如,通过在 person.prototype 中定义 toString 方法,可以改写 Object.prototype 的 toString 方法。
原型方法重写与实例隔离
再看以下代码示例:
代码如下:
function person(name, age) {
this.name = name;
this.age = age;
}
person.prototype.getInfo = function() {
alert("My name is "+this.name+", and I have "+this.age+" years old");
}
var zhangchen = new person("zhangchen", 23);
var luomi = new person("luomi", 23);
zhangchen.getInfo(); // output My name is zhangchen, and I have 23 years old;
luomi.getInfo(); // output My name is luomi, and I have 23 years old;
luomi.getInfo = function() {
alert("here can rewrite the function of getInfo!");
}
luomi.getInfo(); //here can rewrite the function of getInfo!
zhangchen.getInfo(); // output My name is zhangchen, and I have 23 years old;从运行结果可以看到,虽然 person 的每个实例都继承了 person.prototype 中的方法,但我们也可以在实例化的对象中重新定义原型对象中的方法,且这不会影响其他实例。
以上是对原型及原型链继承方式的理解,参考了《JavaScript: 使用面向对象的技术创建高级 Web 应用程序》一文,欢迎大家共同讨论。
JS动态构建复杂嵌套JSON对象的方法
2026-11-05 15:41:52
JS负数取余为什么是负数?详解余数与模运算区别
2026-11-05 13:34:41
JS 解压出现乱码或报错怎么解决?
2026-11-05 12:32:38
JS 中 startsWith、indexOf 与正则判断字符串前缀的对比
2026-11-04 22:19:43
JS解析Excel后怎么将数据转换为JSON格式
2026-11-04 20:58:28
