JavaScript 原型链机制解析:从构造函数到继承
本文深入解析 JavaScript 对象模型,通过构造函数创建对象的过程,阐明 __proto__ 与 prototype 的关系。文章详细推导原型链的形成机制,解释属性查找规则及 Object.prototype 作为基类的作用,揭示 JavaScript 基于原型的继承本质。
引言:对象创建问题
文章从一个问题引入讨论。
代码示例如下: function Base(){} var base = new Base()
上述两行代码执行后,究竟创建了几个对象(object)?
要准确回答这个问题,首先需要明确 JavaScript 中 object 的定义与概念。
JavaScript 对象与类型基础
关于 Objects
在 JavaScript 中,几乎所有事物都是对象,包括 Arrays、Functions、Numbers 以及 Objects 本身。JavaScript 没有类似 C# 中的 class 概念。对象的本质是一个名称-值对的集合,其中名称(name)必须是字符串类型,通常被称为“属性”(property);而值(value)可以是各种类型的对象,如 string、number、boolean、array 或 function 等,这些值即为属性的具体取值。
关于 typeof
既然对象包含数组、函数、数字等多种类型,如何区分它们呢?答案是使用 typeof 操作符。typeof 返回一个字符串,例如 typeof(null) 返回 “object”,typeof(false) 返回 “Boolean”,typeof(1) 返回 “number”。由于 typeof 始终返回字符串,因此对于 typeof(typeof x),无论 x 是什么类型,结果总是 “string”。

构造器与 Function 的创建机制
关于 Constructor
JavaScript 中没有 class,因此也没有传统意义上的类构造函数。那么对象是如何创建的呢?答案是使用构造器(constructor)。构造器实际上就是 Function,因此它本身也是一个 object。开头的 function Base(){} 就是一个构造器,而 var base = new Base() 则是利用这个构造器(通过关键字 new)创建了一个名为 base 的 object。至此可以得出结论:开头的两行代码至少创建了两个 object:一个是 Base,类型为 function 的 object;另一个是 base,类型为 object 的 object。
关于 Function() 和 Object()
这是两个重要的预定义构造器。所有的 function(例如开头的 Base())都是由 Function() 构造出来的;而 Object 的 prototype 将被所有 object 继承,这一点将在后文详细讲解。

Function 的创建过程
当执行 function Base(){this.a = 1} 时,其效果等同于 var Base = new Function(“this.a = 1”)。也就是说,这行代码本身使用了预定义好的 Function() constructor 来构造一个 function 类型的 object(即 Base)。在这个创建过程中,JavaScript 引擎会执行哪些操作呢?
1. 首先,引擎会创建一个 object,Base 指向这个 object。此时 typeof 这个 object 的结果为 “function”。
2. 给 Base 附上 __proto__ 属性,使其等于 Function 这个构造器的 prototype(这也是预定义好的)。这是非常关键且具规律性的一步。(规律:)在执行任意类似 var x = new X() 时,都会把 X 的 prototype 赋给 x 的 __proto__,也就是说,此时 x.__proto__ 和 X.prototype 会指向同一个对象。
3. 为 Base 创建 call 属性,该属性是一个 function。因此我们可以这样调用:Base.Call()
4. 为 Base 创建 Construct 属性,该属性也是一个 function。在执行 var base = new Base() 时,就会调用这个 Construct 属性。
5. 为 Base 创建 Scope、Length 等属性,此处略过。
6. 为 Base 创建 prototype 属性:先用 new Object() 创建一个对象,为该对象创建一个属性叫 constructor,该属性值设置为 Base。再把 Base 的 prototype 设置为这个新创建的对象。伪代码如下:
var x = new Object();
x.constructor = Base;
Base.prototype = x;
现在我们将关注点集中在第 2 步和第 6 步。
__proto__ 与 prototype 的关系
__proto__ 和 prototype
从第 2 步可以看出,任意一个用构造器构造出来的 object(包括 Objects 和 Functions),都会有 __proto__ 属性,指向该构造器的 prototype 属性。需要注意的是,__proto__ 是一个私有属性,在 IE 浏览器上不可见,但在 Chrome 中可以查看到。
从第 6 步可以看出,任意一个用 new Function() 构造出来的 functions,都会有 prototype 属性。该属性是用 new Object() 构建出来的,其初始公开属性只有一个 constructor。

原型链的形成与属性查找
原型链
接下来分析第 6 步的伪代码,即为 function 创建 prototype 的步骤:
var x = new Object(); // 参见2中的规律,会有x.__proto__= Object.prototype。
x.constructor = Base;
Base.prototype = x;
此时我们用 Base() 构造一个对象出来:
var base= new Base(); // 参见2中的规律,会有base.__proto__ = Base.prototype,也就是 = x。
__proto__.__proto__,这就是传说中 JavaScript 对象的原型链!由于用 Function() 创建构造器时的关键第 6 步,保证了所有 object 的原型链的顶端,最终都指向了 Object.prototype。

Property Lookup(属性查找)
如果我们尝试读取某个 object 的某个属性,JavaScript 会如何处理呢?
假设有一个 object 叫 xxx,我们执行 alert(xxx.a),即读取 xxx 的 a 属性。JavaScript 首先会在 xxx 本身寻找 a 属性,如果没找到,则到 xxx.__proto__ 里寻找 a 属性,并沿着原型链向上查找,找到即返回(如果没找到,则返回 undefined)。可以来看个例子:

从上图得知:base 本身是没有 constructor 属性的,但是 base.constructor 确实能返回 Base 这个函数。原因在于 base.__proto__ 有这个属性。(base.__proto__ 是什么?就是 Base.prototype,即在上面构建 Function 的第 6 步伪代码中,为 Base.prototype.constructor 赋值为 Base 本身。)
Object 基类与原型继承
Object 作为“基类”
另外,由于任意 object 的原型链的顶端都是 Object.prototype。因此,Object.prototype 里定义的属性,就会通过原型链被所有 object 继承下来。这样,预定义好的 Object 就成了所有对象的“基类”。这就是原型链的继承机制。

看上图,Object.prototype 已经预定义好了一些属性。如果我们再追加一条属性叫 propertyA,那么这个属性和预定义属性一样,都可以从 base 上读到。
原型继承
我们已经得知:
对于 var xxx = new Object(); 有 xxx.__proto__ = Object.prototype;
对于 var xxx = new Base(); 有 xxx.__proto__.__proto__ = Object.prototype;
这看起来像什么呢?从 C# 的角度看,很像 Base 是 Object 的子类。也就是说,由 Base() 构造出来的 object,比由 Object() 构造出来的 object,在原型链上低一个层级。这是通过把 Base.prototype 指向由 Object() 创建的对象来做到的。那么自然而然,如果我想定义一个继承自 Base 的构造器,只需将该构造器的 prototype 指向一个 Base() 构造出来的对象。
function Derived(){}
var base = new Base();
Derived.prototype = base;
var d = newDerived(); //很容易推算出:d.__proto__.__proto__.__proto__ = Object.prototype.
推算过程:d.__proto__ 指向 Derived.prototype,也就是 base;则 __proto__.__proto__ 指向 base.__proto__,也就是 Base.prototype,也就是某个 new object() 创建出来的对象,假设是 o;则 __proto__.__proto__.__proto__ 指向 o.__proto__,也就是 Object.prototype。
结论与延伸问题
回答开头的问题,以及几个新的问题
那两行代码至少创建了三个对象:Base、base、Base.prototype。顺便说明,base 是没有 prototype 属性的,只有 function 类型的 object,在被构建时才会被创建 prototype 属性。

d.constructor 会返回什么呢?
构造器 Base() 和 Derived() 里都是空的,如果有代码,将会怎么被执行呢?
……
待续。见下篇
ES6模块化中js文件怎么用import和export交互
2026-11-05 17:00:48
JS读取本地文件时报错或无响应的常见原因
2026-11-05 16:32:31
let、const与var的区别:JavaScript变量声明最佳实践
2026-11-05 14:16:38
JS中直接定义静态二维数组的字面量写法
2026-11-05 14:16:08
JS 怎么查找字符串中所有匹配项的位置
2026-11-05 14:15:53
