在构造函数原型上添加方法是最常用且合理的动态扩展方式,因其不改动现有实例、不影响类定义,所有实例共享同一原型并即时获得新方法,符合javascript原型设计本意。

为什么说这是“动态”的?
所谓动态,是指在对象已经存在之后,才决定添加某个行为。比如:
- 用户完成某项操作后,才给实例增加一个 saveToCache 方法;
- 加载完某个模块后,才把 exportData 挂到 Report.prototype 上;
- 运行时检测环境(如是否支持 WebAssembly),再有条件地注入 runInWasm。
怎么写才正确?
关键不是“能不能加”,而是“加到哪儿”——必须加到构造函数的 prototype 上,而不是实例自身或别的地方:
function User(name) {
this.name = name;
}
const u1 = new User('Alice');
const u2 = new User('Bob');
// ✅ 正确:挂到原型,所有实例立即可用
User.prototype.sayHi = function() {
console.log(`Hi, I'm ${this.name}`);
};
u1.sayHi(); // Hi, I'm Alice
u2.sayHi(); // Hi, I'm Bob
常见误区要避开
容易误用的方式,效果完全不同:
- 给实例单独加方法:只影响那个对象,不共享,浪费内存;
- 改写整个 prototype:会丢失 constructor 指向,还可能切断已有实例的原型链;
- 用 __proto__ 修改单个实例原型:虽可行但不推荐,破坏一致性,且性能不可控。
它合理吗?
非常合理,而且是 JavaScript 原型机制的设计本意:
- 符合“公共行为只存一份”的原则,节省内存;
- 利用原型链查找机制,天然支持运行时扩展;
- 已被大量成熟库(如 jQuery、Lodash 的某些插件机制)长期验证;
- 只要不频繁重写整个 prototype,性能开销几乎为零。











