原型/构造函数/实例:三者关系是什么?
面试速答(30 秒版 TL;DR)
- 构造函数(constructor):一个函数(或
class),用new来创建实例。 - 原型对象(prototype object):
Ctor.prototype指向的那个对象,放“实例共享的方法/属性”。 - 实例(instance):
new Ctor()产生的对象,它的[[Prototype]]会指向Ctor.prototype,从而形成原型链。 - 口诀:
Ctor.prototype给实例用;实例的[[Prototype]]指回它;prototype.constructor再指回Ctor。
心智模型:两条链,别混
- 实例的原型链:
obj -> obj[[Prototype]] -> ... -> null - 函数对象自己的原型链:
Ctor -> Ctor[[Prototype]] -> Function.prototype -> Object.prototype -> null
很多人混淆的点是:prototype 是函数对象上的属性;[[Prototype]] 是任意对象都有的内部槽。
图示:把 3 个对象和几条指针画出来
代码:用标准 API 验证关系(避免依赖 __proto__)
function Foo() {}
const foo = new Foo();
console.log(Object.getPrototypeOf(foo) === Foo.prototype); // true
console.log(Foo.prototype.constructor === Foo); // true
console.log(Object.getPrototypeOf(Foo) === Function.prototype); // true
console.log(Object.getPrototypeOf(Foo.prototype) === Object.prototype); // true
console.log(Object.getPrototypeOf(Object.prototype) === null); // true
你在面试里可以用一句话解释 new:
new Foo()会创建对象o,把o[[Prototype]]设为Foo.prototype,再用Foo以this=o执行,最后返回o(除非构造函数显式返回一个对象)。
常见追问
Q1:prototype 和 [[Prototype]] 有什么区别?
prototype:函数对象的属性,决定“用它new出来的实例”原型指向哪里。[[Prototype]]:对象的内部槽,决定“属性查找往上委托”的路径。
Q2:为什么 Foo.prototype.constructor 能指回 Foo?
因为默认情况下 JS 会在创建函数时初始化 Foo.prototype,并在其上放一个 constructor 指回函数本身(但你手动替换 Foo.prototype 时可能破坏它,见下一篇)。
易错点/坑
__proto__是历史遗留访问器,不推荐作为面试或生产代码的“规范写法”,优先用Object.getPrototypeOf/Object.setPrototypeOf。- 只有“可构造的函数”才有
prototype(例如箭头函数没有prototype,不能new)。
速记要点(可背诵)
prototype在构造函数上,[[Prototype]]在对象上。- 实例通过
[[Prototype]]连接到Ctor.prototype,方法共享靠原型链委托。