javascript运行时多态依赖__proto__链方法查找而非重写prototype指针;真正起作用的是在原型或实例上覆盖同名方法,按实例→原型→父原型顺序取最近实现。

动态重写 prototype 指针本身并不能直接实现运行时多态——真正起作用的是对 prototype 对象上方法的重定义,而非修改 prototype 的引用地址。JavaScript 中的多态行为依赖于运行时沿 __proto__ 链查找同名方法的机制,只要不同对象(或其原型)提供了同名但逻辑不同的实现,调用时就会自动取“最近”的那个版本。
明确 prototype 指针不是“可重写”的目标
所谓“重写 prototype 指针”,容易误解为像 obj.prototype = newProto 这样操作——但普通实例没有 prototype 属性,只有函数才有;而修改构造函数的 prototype 属性,影响的是后续新创建的实例,不会改变已有实例的 __proto__ 链。因此:
- 实例的原型链在创建时就固定为
instance.__proto__ === Constructor.prototype - 改写
Constructor.prototype只会让新实例继承新行为,老实例仍沿原链查找 - 真正实现多态扩展,是往现有原型上添加/覆盖方法,或给实例自身赋值同名方法(高优先级)
通过原型方法覆盖模拟运行时多态
这是最常用、语义清晰的方式,适用于有明确继承层级的场景(如 UI 组件、数据模型):
- 定义基类构造函数,并在其
prototype上挂载默认方法:function Animal() {}Animal.prototype.speak = function() { console.log('makes a sound'); }; - 子类通过
Object.create(Animal.prototype)建立原型链,并修复constructor - 在子类原型上定义同名方法:
Dog.prototype.speak = function() { console.log('woof!'); }; - 创建
new Dog()和new Cat()后,都调用.speak(),输出各自实现
运行时动态注入行为(不依赖继承)
适合插件化、策略模式等灵活扩展场景,核心是“鸭子类型”+存在性判断:
- 写一个通用执行器:
function runAction(obj) { if (typeof obj.execute === 'function') obj.execute(); } - 任意对象只要带
execute方法,就能被统一调度:runAction({ execute() { console.log('start server'); } });runAction({ execute() { console.log('send email'); } }); - 无需修改任何
prototype,也不需要构造函数,行为由传入对象决定
注意方法查找优先级与覆盖时机
引擎总是取“最近”的同名方法,顺序为:实例自身 → 构造函数 prototype → 父级 prototype……
- 给实例直接加方法:
dog.speak = function() { console.log('override at instance'); };—— 会屏蔽原型链上的所有同名实现 - 动态替换原型上的方法:
Animal.prototype.speak = function() { console.log('new default'); };—— 所有未覆盖该方法的实例都会立即生效(包括已创建的) - 但若子类已在其 prototype 上定义了
speak,则父类 prototype 的修改对其无影响











