装饰器本质是接收目标函数并返回新函数的高阶函数;它不修改原函数,而通过包裹逻辑实现调用前后增强,需用fn.apply(this, args)保证this和参数透传。

装饰器本质是高阶函数
JavaScript 中的装饰器(Decorator)目前仍是 Stage 3 提案,尚未进入正式标准,所以不能直接在原生环境(如浏览器控制台或 Node.js 默认模式)中使用 @ 语法。所谓“装饰器增强函数”,实际是通过一个接收目标函数、返回新函数的高阶函数来实现逻辑注入——它不修改原函数,而是在调用前后插入额外行为。
用函数模拟装饰器最稳妥
绕过编译工具(如 Babel、TypeScript)也能立即生效的方式,就是手动写一个装饰器函数。常见需求如日志、防抖、权限校验,都可以这样封装:
function logDecorator(fn) {
return function(...args) {
console.log(`[log] 调用 ${fn.name},参数:`, args);
const result = fn.apply(this, args);
console.log(`[log] 返回值:`, result);
return result;
};
}
function add(a, b) {
return a + b;
}
const loggedAdd = logDecorator(add);
loggedAdd(2, 3); // 输出日志 + 返回 5
-
logDecorator接收函数fn,返回一个新函数,该函数内部调用fn并包裹逻辑 - 必须用
fn.apply(this, args)保证this和参数透传,否则上下文会丢失 - 不要直接改写
fn.prototype或用bind简化,那会破坏原函数的this绑定和参数长度(fn.length)
类方法装饰器需注意 this 绑定失效
给类方法加装饰器时,若直接在类定义里写 @logDecorator(启用实验性语法),运行时该方法常会丢失 this,因为装饰器返回的新函数未自动绑定实例。解决方式只有两种:
- 在构造函数中手动绑定:
this.method = logDecorator(this.method).bind(this) - 改用箭头函数定义方法(但会失去原型继承优势)
- 更推荐:装饰器内部用
return function(...args) { ... }.bind(this)显式绑定(但需确保装饰器能访问到实例上下文)
多数真实项目中,直接用 logDecorator(target[key]) 手动包装方法比依赖 @ 语法更可控。
立即学习“Java免费学习笔记(深入)”;
TypeScript 中开启装饰器要配两个开关
如果用 TypeScript,必须同时设置以下两项才能让 @ 语法被识别且生成有效代码:
-
"experimentalDecorators": true(允许语法解析) -
"emitDecoratorMetadata": true(生成元数据,仅当需要反射时才必需)
但要注意:即使配置正确,TS 编译后仍只是把 @decorator 转成类似 __decorate([decorator], ...) 的辅助调用,底层还是靠你写的装饰器函数执行。没有那个函数,@ 就是无效标记。
真正起作用的永远是你定义的那个接收 target、propertyKey、descriptor 的函数,而不是 @ 符号本身。











