JavaScript原型链原理详解:从new到__proto__

作者:函数茶馆时间:2026-10-24 13:36:23浏览:307

本文深入解析JavaScript原型链的核心机制,详细拆解new操作符的三步执行过程,重点阐述__proto__在属性查找中的关键作用。通过代码示例演示原型链的构建与属性访问路径,揭示prototype作为辅助角色与__proto__作为本质连接的关系,帮助开发者彻底理解对象继承原理。

new操作符的执行步骤解析

首先观察以下代码片段:


代码如下:

 
<script type="text/javascript">
var Person = function () { };
var p = new Person();
</script>

这段代码非常基础,但我们需要深入探究new关键字具体执行了哪些操作。可以将new的过程分解为以下三个步骤:



<1> var p={}; 即初始化创建一个空对象p。



<2> p.__proto__=Person.prototype; 将实例的__proto__指向构造函数的prototype。



<3> Person.call(p); 即调用构造函数初始化p,这一步也可以理解为对p进行初始化。



其中的关键步骤是第二步,我们可以通过代码来验证其正确性:


代码如下:

 
<script type="text/javascript">
var Person = function () { };
var p = new Person();
alert(p.__proto__ === Person.prototype);
</script>

执行这段代码会返回true,证实了步骤2的描述是正确的。



__proto__与原型链的基本概念

那么__proto__究竟是什么?这里简要说明:每个对象内部都会初始化一个名为__proto__的属性。当访问对象的某个属性时,如果该对象自身不存在此属性,引擎就会去__proto__指向的对象中查找。而__proto__指向的对象又拥有自己的__proto__,如此层层递进查找,便形成了我们常说的原型链。



按照ECMAScript标准,__proto__属于非标准私有属性,不应当对外公开。然而,Firefox浏览器引擎将其暴露为公共属性,允许外部访问和设置。



原型链属性查找机制示例

概念阐述清楚后,让我们通过以下代码进行实践:


代码如下:

 
<script type="text/javascript">
var Person = function () { };
Person.prototype.Say = function () {
alert("Person say");
} 
var p = new Person();
p.Say();
</script>

这段代码十分简单,相信大家都写过类似的代码。现在我们来分析为什么实例p能够访问Person构造函数原型上的Say方法。



首先,通过var p=new Person()可知p.__proto__=Person.prototype。当我们调用p.Say()时,引擎首先在p自身查找Say属性,未找到后,便沿着__proto__指向Person.prototype进行查找。由于我们在前文定义了Person.prototype.Say=function(){},因此成功找到了该方法。



复杂原型链推导与总结

接下来,我们看一个更复杂的继承场景:


代码如下:

 
<script type="text/javascript">
var Person = function () { };
Person.prototype.Say = function () {
alert("Person say");
} 
Person.prototype.Salary = 50000;
var Programmer = function () { };
Programmer.prototype = new Person();
Programmer.prototype.WriteCode = function () {
alert("programmer writes code");
}; 
Programmer.prototype.Salary = 500;
var p = new Programmer();
p.Say();
p.WriteCode();
alert(p.Salary);
</script>

我们来逐步推导其原型链结构:



由var p=new Programmer()可知p.__proto__=Programmer.prototype;。



而在前文中我们指定了Programmer.prototype=new Person();。我们可以将其拆解为:var p1=new Person(); Programmer.prototype=p1; 此时:



p1.__proto__=Person.prototype;



Programmer.prototype.__proto__=Person.prototype;



结合前文得到的p.__proto__=Programmer.prototype,可以推导出p.__proto__.__proto__=Person.prototype。



理清关系后,我们来看上述代码的执行结果。调用p.Say()时,由于p自身没有Say属性,引擎前往p.__proto__(即Programmer.prototype,也就是p1)查找,发现p1中也没有Say,于是继续前往p.__proto__.__proto__(即Person.prototype)查找,最终找到了alert(“Person say”)的方法。



其他属性的查找逻辑也是同样的道理。



这就是原型链的实现原理。



最后需要明确的是,prototype实际上只是一个辅助概念,它在原型链构建中主要起到桥梁作用,特别是在new操作时具有特定价值。而原型链的本质连接,其实在于__proto__!

作者最新文章