prototype与__proto__指向堆内存中同一对象地址,前者是函数的属性,后者是实例的内部引用;函数对象同时拥有二者,分别指向不同内存地址以构成原型链。

要从内存物理拓扑角度理解 prototype 与 __proto__ 的关系,关键不是画抽象图,而是看清它们在堆内存中实际指向的**同一块对象地址**——它们是不同对象上、指向相同内存位置的两个引用字段。
prototype 是函数对象身上的“出厂说明书”
prototype 是每个函数(包括内置构造器如 Object、Array 和自定义函数)在创建时自动拥有的属性,它本身就是一个普通对象,存储在堆内存某处。这个对象的唯一使命,就是作为将来用 new 创建实例时,那些实例的 __proto__ 所该指向的目标。
- 例如:
function Person() {}执行后,引擎在堆中分配一块内存存放Person.prototype对象,其内部含constructor等属性; - 这块内存地址是固定的,比如假设为
0xabc123; - 它不依赖任何实例存在——哪怕你从不调用
new Person(),Person.prototype对应的内存块依然存在。
__proto__ 是实例对象身上的“寻址指针”
__proto__(即规范中的 [[Prototype]])是每个对象(包括函数对象自身)内部的一个隐藏引用字段,它在对象被创建时就被初始化,值就是其构造器的 prototype 所在的内存地址。
- 执行
const p = new Person()时,引擎创建新对象p,并在其内存布局中写入一个指针字段[[Prototype]] = 0xabc123; - 这个
0xabc123就是上面Person.prototype所在的物理地址; - 所以
p.__proto__ === Person.prototype本质是两个变量指向同一块堆内存——不是“相等”,而是“同址”。
函数对象同时拥有两种角色,因此有两种指针
函数既是可调用对象,又是构造器,所以它身上既有 prototype(供别人继承),也有 __proto__(自己继承谁):
-
Person.__proto__指向Function.prototype(因为Person是函数,而所有函数都是Function的实例); -
Person.prototype是另一块独立内存,供new Person()出来的实例去链接; - 二者地址不同:
Person.__proto__≈0xdef456,Person.prototype≈0xabc123; - 这种双重身份,正是原型链能向上连到
Function.prototype → Object.prototype → null的物理基础。
Object.create() 直接操作内存指针,绕过构造逻辑
使用 Object.create(parent) 时,引擎直接在新对象的 [[Prototype]] 字段填入 parent 的内存地址,不触发任何构造函数。
- 这相当于手动设置
__proto__指向,完全跳过prototype的中介角色; - 对比
Child.prototype = new Parent():后者会执行Parent(),可能产生副作用,且让Child.prototype多出不必要的实例属性; - 而
Child.prototype = Object.create(Parent.prototype)只做一件事:把Child.prototype的[[Prototype]]设为Parent.prototype地址,干净、精准、无副作用。











