跳到主要内容

原型对象和构造函数有何关系?

面试速答(30 秒版 TL;DR)

  • 关系一:构造函数的 prototype 属性指向一个“原型对象”,它会成为 new 出来实例的 [[Prototype]]
  • 关系二:原型对象上通常有个 constructor 指回构造函数(默认如此,但可被你改坏)。
  • 关系三:把方法挂到 Ctor.prototype 上,能让所有实例共享一份函数实现,避免每个实例都拷贝一套方法。

关键机制:new 只关心 Ctor.prototype

new Ctor() 的核心连接动作是:

  • Object.getPrototypeOf(instance) === Ctor.prototype

所以你可以把“原型对象”讲成:

  • Ctor.prototype 是实例原型链的第一个跳板(第一站)。”

示例 1:为什么把方法放在 prototype 上?

function User(name) {
this.name = name;
}

User.prototype.sayHi = function () {
return `hi, ${this.name}`;
};

const a = new User("a");
const b = new User("b");

console.log(a.sayHi()); // hi, a
console.log(a.sayHi === b.sayHi); // true (共享同一个函数)

如果把 sayHi 写在构造函数里(this.sayHi = ...),那每次 new 都会创建一份新函数,不利于内存与一致性。


示例 2:为什么“替换 prototype”经常要补 constructor?

function Foo() {}

Foo.prototype = { x: 1 };

console.log(Foo.prototype.constructor === Foo); // false
console.log(Foo.prototype.constructor === Object); // true (通常会变成 Object)

修复方式(让 constructor 指回去,且保持不可枚举):

function Foo() {}

Foo.prototype = { x: 1 };
Object.defineProperty(Foo.prototype, "constructor", {
value: Foo,
writable: true,
configurable: true,
enumerable: false,
});

图示:一正一反两条指针


常见追问

Q1:所有函数都有 prototype 吗?

不是。箭头函数没有 prototype,也不能作为构造函数使用。

Q2:class 和原型是什么关系?

class 只是语法糖:class C { m() {} } 的实例方法本质仍在 C.prototype.m 上;面试时用“底层仍是原型链委托”即可。


易错点/坑

  • 别把 Ctor.prototype(原型对象)和 Ctor[[Prototype]](函数对象自己的原型)混为一谈。
  • Object.setPrototypeOf 动态改原型会影响引擎优化,通常不推荐在热路径使用。

速记要点(可背诵)

  • Ctor.prototype 决定实例“往上找”的第一站。
  • prototype.constructor 只是一个普通属性,可能被你替换原型时破坏。