proto-prototype-constructor

__proto__、prototype、constructor 三者关系拆解。

#type / concept #status / growing #resource / javascript #resource / ecmascript

[!info] related notes

__proto__prototypeconstructor 三者关系

一句话定义

  • __proto__ 是每个实例指向其构造函数 prototype 的链接(原型链的连接线)
  • prototype构造函数独有的属性,存放所有实例共享的方法
  • constructorprototype 上的属性,指回构造函数本身

核心机制 / 工作原理

三者的关系图

function Foo() {}

foo = new Foo()

  foo.__proto__  ----->  Foo.prototype
                          |
                          | .constructor
                          |
                          v
                        Foo

核心等式

function Foo() {}
const foo = new Foo();

// 1. 实例的 __proto__ 指向构造函数的 prototype
foo.__proto__ === Foo.prototype;          // true

// 2. prototype 上的 constructor 指回构造函数
Foo.prototype.constructor === Foo;        // true

// 3. 由此推导
foo.__proto__.constructor === Foo;        // true
foo.constructor === Foo;                  // true(沿原型链查找到)

prototype 链的逐级查找

foo.hasOwnProperty('toString')  // false
// 查找过程:
// 1. foo 自身没有 toString
// 2. foo.__proto__ (= Foo.prototype) 没有 toString
// 3. Foo.prototype.__proto__ (= Object.prototype) 找到了 toString

完整链:foo -> Foo.prototype -> Object.prototype -> null

constructor 不是”自带的”

constructor 是在创建函数时,JS 引擎自动在 Foo.prototype 上设置的。但如果手动覆盖了 prototype

Foo.prototype = {}; // 覆盖了整个 prototype
// 此时 Foo.prototype.constructor 丢失,变成 Object
// 修复:Foo.prototype.constructor = Foo;

最小例子

function Person(name) {
  this.name = name;
}
Person.prototype.greet = function () {
  return 'Hi, ' + this.name;
};

const p = new Person('Alice');

// 验证三者关系
p.__proto__ === Person.prototype;           // true
Person.prototype.constructor === Person;    // true
p.__proto__.constructor === Person;         // true

// 原型链查找
p.greet();          // 'Hi, Alice'  — 从 Person.prototype 上找到
p.constructor;      // Person       — 从 Person.prototype.constructor 找到
p instanceof Person; // true

边界与常见误解

  • “每个对象都有 prototype” — 错。只有函数才有 prototype 属性。普通对象只有 __proto__
  • __proto__ 是标准”__proto__ 是非标准的访问方式(虽然所有浏览器都支持)。标准方式是 Object.getPrototypeOf(obj)
  • “constructor 是只读的” — 不是。constructor 可以被覆盖,覆盖后 instance.constructor 会指向错误的构造函数。
  • 覆盖 prototype 后忘记修复 constructor — 这是经典 bug。Person.prototype = {} 之后,p.constructor 变成 Object 而不是 Person
  • 箭头函数没有 prototype — 箭头函数不能作为构造函数,没有 prototype 属性。
创建于 2026/3/15 更新于 2026/5/27