javascript动态方法绑定本质是原型链查找加运行时调用,支持方法重写、鸭子类型和运行时行为修改,无需编译时类型声明或显式类型判断。

JavaScript 的动态方法绑定,本质就是靠原型链查找 + 运行时调用实现的——不需要编译时类型声明,也不需要显式判断对象种类,只要调用时能顺着原型链找到对应方法,就直接执行。
方法重写:子类覆盖父类同名方法
这是最典型的动态绑定场景。子构造函数或 class 通过修改自身原型上的同名方法,让所有实例(包括已创建的)在调用时自动走新逻辑。
- 用 Object.create(Animal.prototype) 设置子类原型后,在 Dog.prototype.speak 上定义新实现,就完成了对父类方法的覆盖
- ES6 中写 class Dog extends Animal { speak() { ... } } 更简洁,但底层仍是把方法挂到 Dog.prototype 上
- 关键点:每次调用 dog.speak() 时,引擎从 dog 自身开始查,没找到就沿 __proto__ 向上,最先匹配的那个 speak 就被执行
鸭子类型:只看有没有方法,不看是谁造的
完全脱离继承关系,只要对象有某个方法名,就能被统一函数处理。这种结构匹配才是 JS 最自然、最轻量的多态形式。
- 比如函数 function perform(action) { action.run(); },传入 { run() { console.log('car'); } } 或 { run() { console.log('robot'); } } 都能运行
- 不需要 instanceof 判断,也不依赖共同父类,只要“会 run”,就被视为合法参数
- 适合策略模式、插件系统等场景,新增行为不影响原有调用方代码
动态绑定:方法归属在调用那一刻才确定
JS 不会在定义时锁定方法属于谁,而是在每次调用时实时查找原型链。这意味着你可以在运行中随时改变行为。
- 修改 Dog.prototype.speak = function() { ... } 后,之前创建的所有 new Dog() 实例,下次调用 speak() 就会执行新逻辑
- 甚至可以临时给单个实例加方法:myDog.speak = function() { ... },它会优先于原型链上的同名方法(因为查找从实例自身开始)
- 这种灵活性是静态语言不具备的,也是 JS “动态多态”的核心体现
注意属性和方法的查找差异
原型链只负责方法和可继承属性的查找;实例自身的属性(如 this.name)不会被原型上的同名属性覆盖,也不会沿链查找。
- 如果 Animal 构造函数里写了 this.type = 'animal',每个实例都有自己的 type,互不影响
- 但调用 this.speak() 时,引擎会跳过实例自身的 speak(除非真有),转而查原型链
- 分清这个区别,才能准确预测“哪个方法被调用”、“哪个值被读取”











