深入理解JavaScript原型链:从prototype属性到继承机制
本文深入解析JavaScript中prototype与__proto__的内部机制,阐明原型链的构建过程。通过Staff与ManStaff类的示例,展示如何利用prototype实现对象继承,并分析属性查找规则及Object作为基类的角色,帮助开发者理解JS面向对象的核心原理。
prototype属性与对象共享机制
在JavaScript中,每个函数都包含一个prototype属性,该属性指向一个对象类型的实例。所有通过该函数构造器创建的对象,都会共享这个prototype上的属性和方法,这意味着可以直接通过实例访问这些定义在原型上的成员。
以下代码演示了prototype的基本用法:
function Staff(name) {
this.name = name;
}
Staff.prototype.say = function() {
alert(this.name + " say hello");
}
var staff1 = new Staff("hunter");
var staff2 = new Staff("dangjian");
staff1.say();
staff2.say(); 运行上述程序可以发现,通过原型定义的方法和属性可以被所有实例调用。更关键的是,这些属性和方法在同类对象之间是共享的,而非每个实例单独拥有。
验证代码如下:
alert( staff1.say == staff2.say); prototype的另一个重要特性是支持通过它来构建对象的继承关系。具体做法是将基类的一个实例赋值给子类的prototype属性,从而模拟面向对象语言中的继承机制。这是JavaScript实现面向对象编程的核心方式之一。下面的代码展示了如何利用这一特性建立继承:
代码如下:
function Staff(name) { // 基类
this.name = name;
}
Staff.prototype.say = function() {
alert(this.name + " say hello");
}
function ManStaff(name, age) { // 子类
this.name = name;
this.age = age;
}
ManStaff.prototype = new Staff(); // 建立继承关系
var manStaff1 = new ManStaff("hunter", 22);
var manStaff2 = new ManStaff("dangjian", 32);
manStaff1.say();
manStaff2.say(); prototype内部机制与原型链构建
运行代码可见,ManStaff对象获得了基类Staff中的say方法。这种继承机制在JavaScript中依赖于原型链(prototype chain)来实现。除了掌握用法,理解其背后的内部机制对于开发者同样重要。接下来我们将剖析prototype的工作原理及原型链的具体实现过程。
要透彻理解prototype机制,首先必须了解JavaScript中函数的创建原理。
当代码执行到function Staff(name) {this.name = name;}时,解释器实际上执行了类似var Staff = new Function("name", "this.name = name")的操作。解释器会使用预定义的Function()构造函数,创建一个function类型的对象,即Staff。
随后,系统会为创建的Staff对象添加__proto__属性,并将其值指向Function构造器的prototype。这一步骤在所有对象创建过程中都会发生,例如执行var x = new X()时,系统会将X的prototype赋值给x的__proto__。具体赋值逻辑如下:
代码如下:
Staff.__proto__ = Function.prototype; 接下来,系统会为Staff创建prototype属性。这是创建function类型对象时的特有步骤,其内部伪代码执行过程如下:
代码如下:
var o = new Object();
o.constructor = Base;
Staff.prototype = o; 综上所述,创建普通对象时会生成一个私有属性__proto__,而创建函数对象时则会额外生成一个prototype属性。由于Staff是一个function类型的对象,因此它同时具备这两个关键属性。
这两个属性是构建原型链的核心。我们来分析执行var staff1 = new Staff("hunter")时,原型是如何传递的。
根据前述分析,staff1.__proto__指向Staff.prototype。而Staff.prototype本身是一个由Object创建的对象,因此Staff.prototype.__proto__指向Object.prototype。由此可得staff1.__proto__.__proto__指向Object.prototype,即staff1.__proto__.__proto__ == Object.prototype。这就是原型链的定义:当访问对象的某个属性时,JavaScript引擎会先在对象自身查找,若未找到,则沿着原型链逐级向上查找。
基于原型链的对象继承实现
明确了原型链的原理,构建JavaScript中的对象继承便变得直观。
由上述分析可知,原型链的终点始终是Object.prototype。这意味着在继承体系中,Object是所有对象的最终基类。可以通过以下代码进行验证:
代码如下:
Object.prototype.location = "China";
function Staff(name) { // 基类
this.name = name;
}
Staff.prototype.say = function() {
alert(this.name + " say hello");
}
var ManStaff1 = new Staff("hunter");
var ManStaff2 = new Staff("dangjian");
alert(ManStaff1.location);
alert(ManStaff2.location); 运行结果显示,Object确实是Staff的基类。那么,如何构建Staff的子类呢?
理解了函数的创建原理,我们可以写出如下代码:
代码如下:
function Staff(name) { // 基类
this.name = name;
}
Staff.prototype.say = function() {
alert(this.name + " say hello");
}
function ManStaff(name, age) { // 子类
Staff.call(this,name);
this.age = age;
}
ManStaff.prototype = new Staff(); // 建立继承关系
var ManStaff1 = new ManStaff("hunter", 22);
var ManStaff2 = new ManStaff("dangjian", 32);
ManStaff1.say();
ManStaff2.say(); 建立继承关系的关键语句是:ManStaff.prototype = new Staff()。其继承链推导如下:ManStaff1.__proto__指向ManStaff.prototype,ManStaff.prototype.__proto__指向Staff.prototype,Staff.prototype.__proto__指向Object.prototype;因此ManStaff1.__proto__.__proto__.__proto__最终指向Object.prototype。
JavaScript中的这种继承关系相比传统面向对象语言更为松散,构建方式也相对晦涩,但作为脚本语言,其功能已足够强大。
JS split切割后出现空字符串怎么过滤
2026-11-05 16:00:30
在 React 或 Vue 项目中封装使用 JS 节流防抖
2026-11-05 15:27:29
JavaScript中怎么将带小数的字符串转为整数?
2026-11-05 14:32:38
怎么用JavaScript策略模式重构电商促销计算逻辑?
2026-11-05 14:01:09
JS使用constructor判断数据类型可靠吗
2026-11-05 13:49:41
