动态原型模式通过运行时向构造函数prototype添加方法,使所有新旧实例立即共享更新,原理是原型链的动态查找机制;需避免实例属性遮蔽,并禁用整体替换原型等破坏链结构的操作。

不需要“无感注入”或“强制同步”——只要操作得当,新行为对已有实例天然生效。关键在于理解原型链是运行时查找机制,不是创建时的快照。
直接往构造函数 prototype 上添加方法
这是最自然、最安全的方式。所有已存在和未来创建的实例都会立即获得该能力。
- 例如:
User.prototype.logout = function() { this.session.destroy(); };,所有已登录的new User()实例马上能调用.logout() - 批量添加可用
Object.assign(User.prototype, { validate() {}, serialize() {} }) - 注意:必须确保没有同名实例属性遮蔽它(如
user.logout = ...),否则原型上的更新不会被访问到
修正 bug 或覆盖已有方法
运行时替换原型上的函数,所有未遮蔽的实例下次调用即走新逻辑。
- 比如修复数组
map的兼容性问题:Array.prototype.map = function(...) { ... };,所有已有数组立刻使用新版 - 设置默认值也一样有效:
Request.prototype.timeout = 3000;,此前创建但未设 timeout 的请求实例,读取.timeout就返回 3000 - 原理:每次访问都沿
__proto__动态查找,查到的就是当前 prototype 上的最新定义
避免破坏原型链结构的操作
有些做法看似“更彻底”,实则引入风险或无效。
- 不要整体替换
Constructor.prototype(如Child.prototype = new Parent()后再加方法),否则已有实例仍连着旧 prototype,无法感知新增内容 - 不推荐用
Object.setPrototypeOf(instance, NewProto)强行切换单个实例的原型——性能差、不可靠、部分环境不支持,且违背原型设计本意 - 若真需隔离行为,应改用组合或 Proxy,而不是修补原型链
检查并清理遮蔽(常见失效原因)
很多“没生效”的情况,其实是实例自身已有同名属性,把原型上的覆盖了。
- 用
instance.hasOwnProperty('methodName')判断是否被遮蔽 - 确认被遮蔽后,可删掉实例属性:
delete instance.methodName,之后访问就会落到原型上 - 动态原型模式中常用判断:
if (typeof this.method !== 'function') { Constructor.prototype.method = ... },防止重复定义,也规避遮蔽干扰











