JavaScript多态依赖运行时原型链查找与重定向实现,子类原型指向父类实例以继承方法,同名方法就近覆盖,无需编译时类型声明,仅需对象具备对应方法即可调用。

JavaScript 中的多态不是靠编译时类型系统保障的,而是靠运行时动态查找方法 + 原型链重定向天然实现的。关键不在于“声明多态”,而在于“调用时自动走对的方法”——这背后的核心动作就是:把子类的原型指向父类实例(即原型重定向),同时允许子类在自身构造函数或原型上定义同名方法,从而覆盖查找路径上的旧实现。
原型重定向是继承成立的前提
所谓原型重定向,是指让子类的 prototype 指向一个父类的实例(而非父类构造函数本身)。这样,当访问子类实例上不存在的属性或方法时,JS 引擎会顺着 __proto__ 链向上查找,最终落到父类原型上。
- 不做重定向:Son.prototype = Father; → 子类原型直接等于构造函数,无法继承实例方法和共享属性
- 正确重定向:Son.prototype = new Father(); → 子类原型是一个真实父类实例,具备父类初始化后的状态和方法
方法重写发生在原型链的“就近原则”上
JS 查找方法时遵循“先找自己,再找原型”,这个顺序决定了重写是否生效:
- 如果子类构造函数中通过 this.say = function(){...} 定义了方法,该方法绑定在实例上,优先级最高
- 如果子类在 Son.prototype.say = function(){...} 上定义,它会覆盖 Father.prototype.say,因为 Son.prototype 在查找链中比 Father.prototype 更靠近实例
- 只要 Son.prototype 上存在 say 方法,哪怕 Father.prototype.say 也存在,引擎也不会继续往上找
ES6 class 的本质仍是原型重定向
class Son extends Father 看似语法糖,但 Babel 或 V8 内部仍会执行类似操作:
- 设置 Son.prototype.__proto__ = Father.prototype(非 new Father(),而是直接链到父类原型)
- 确保 super() 调用能正确初始化 this,并把父类构造逻辑注入子类实例
- 子类中定义的同名方法(如 say())自动挂载到 Son.prototype,自然遮蔽 Father.prototype.say
多态调用不需要类型声明,只依赖对象实际结构
你不需要写 Animal a = new Dog() 这样的类型断言。只要两个对象都有 say 方法,就可以被同一段代码调用:
function makeSound(animal) { animal.say(); }makeSound(new Dog()); // 输出“汪汪”
makeSound(new Cat()); // 输出“喵喵”
这里的多态成立,不是因为 Dog 和 Cat 共享某个接口类型,而是因为它们各自在原型链上提供了 say 方法——JS 不检查“是不是 Animal 的子类”,只检查“有没有 say 这个可执行的东西”。这就是鸭子类型 + 原型重定向共同支撑的轻量级多态。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











