原型链装饰是最贴近原生特性的运行时增强方式:通过新建构造函数继承并扩展原型,或包装方法保持this指向,支持实例级动态挂载,零编译、高可控,适用于调试打点等场景。

直接在原型链上挂载增强方法,是最贴近 JavaScript 原生特性的装饰方式——不侵入原构造函数,也不依赖编译器,靠的是对 prototype 和 Object.create 的精准控制。
用新构造函数继承并扩展原型
核心是“新建一个装饰类”,让它继承原始类的原型,再往自己的 prototype 上添加新行为:
- 定义装饰器函数,接收原始构造函数
Target - 内部声明新构造函数
Decorator,调用Target.call(this, ...args)保证初始化逻辑执行 - 设置
Decorator.prototype = Object.create(Target.prototype),建立原型继承链 - 在
Decorator.prototype上添加装饰方法(如logAction()、validate()) - 返回
Decorator,它既能调用原始方法,又能使用新增能力
单个方法级装饰:包装 + 绑定上下文
针对已有对象的某个方法做增强(比如加日志、节流),更轻量且无需改类结构:
- 取到原方法:
const original = obj[key]或descriptor.value - 用高阶函数包裹:
function(...args) { /* 前置逻辑 */; const ret = original.apply(this, args); /* 后置逻辑 */; return ret; } - 关键点:必须用
apply(this, args)保持this指向实例,不能简单调用original(...args) - 赋值回实例属性(安全)或原型属性(影响所有实例,慎用)
避免污染原型,推荐实例级动态挂载
想只增强当前对象,又不想手动一个个赋值?可以用 Object.assign 或临时桥接:
- 创建装饰器时,不改
Target.prototype,而是把增强方法复制到实例自身:Object.assign(obj, { logAction() { ... } }) - 或者用
Object.setPrototypeOf(obj, enhancedProto)临时替换原型(注意不可逆,慎用于长期对象) - 多个装饰叠加时,每次返回新实例或新构造函数,避免层层覆盖导致原始引用丢失
和现代装饰器语法的区别与取舍
ES 提案中的 @decorator 是语法糖,底层仍靠 descriptor 操作;而原型链方式更底层、更可控:
-
@语法适合类/方法层级的声明式增强,需 Babel 或 TypeScript 支持 - 原型链方式适合运行时动态注入,比如调试时给第三方库实例加日志,或脚本中临时打点
- 前者类型友好、可静态分析;后者零编译、即插即用,但要自己管好
this和引用链











