JavaScript无原生拦截器,但可通过高阶函数(如withAuth、withLog)、Proxy(拦截对象方法)或装饰器(@Log)在函数调用前后插入逻辑,实现权限校验、日志等横切关注点。

JavaScript 中没有原生的“拦截器”概念(像 Java Spring 或 Axios 那样的声明式拦截器),但可以通过函数包装、代理(Proxy)、高阶函数等方式,**在函数调用前后插入逻辑,从而控制执行流程**。核心思路是:不直接调用原函数,而是通过中间层介入。
用高阶函数实现调用前/后拦截
这是最常用、最轻量的方式:把目标函数传入一个“拦截函数”,返回一个增强后的新函数。
- 适合统一处理日志、权限校验、参数预处理、结果格式化等场景
- 可链式组合多个拦截逻辑(如先校验 → 再日志 → 最后执行)
示例:
function withAuth(fn) {
return function(...args) {
if (!localStorage.token) {
throw new Error('未登录');
}
return fn.apply(this, args);
};
}
<p>function withLog(fn) {
return function(...args) {
console.log(<code>调用 ${fn.name},参数:</code>, args);
const start = Date.now();
const result = fn.apply(this, args);
console.log(<code>${fn.name} 执行耗时:${Date.now() - start}ms</code>);
return result;
};
}</p><p>const fetchData = () => fetch('/api/data').then(r => r.json());
const guardedFetch = withLog(withAuth(fetchData));
// 调用 guardedFetch() 会先检查登录,再打日志,最后执行用 Proxy 拦截对象方法调用
当需要批量拦截某个对象的**所有方法**(或按规则匹配的方法)时,Proxy 更灵活。它能捕获 apply、get 等操作。
立即学习“Java免费学习笔记(深入)”;
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 适用于 API 客户端、服务类、控制器对象等有多个方法的场景
- 可基于方法名动态决定是否拦截、如何拦截
示例(拦截对象所有函数属性):
function createInterceptor(target, options = {}) {
return new Proxy(target, {
get(obj, prop) {
const value = obj[prop];
if (typeof value === 'function') {
return function(...args) {
if (options.before?.(prop, args) === false) return; // 阻断执行
const result = value.apply(obj, args);
options.after?.(prop, args, result);
return result;
};
}
return value;
}
});
}
<p>const api = {
getUser(id) { return { id, name: 'Alice' }; },
saveUser(user) { return 'ok'; }
};</p><p>const interceptedApi = createInterceptor(api, {
before(method, args) {
console.log(<code>即将调用 ${method}</code>, args);
},
after(method, args, result) {
console.log(<code>${method} 返回:</code>, result);
}
});</p><p>interceptedApi.getUser(123); // 触发 before + after用装饰器语法(需 Babel / TypeScript 支持)
TypeScript 或使用 Babel(启用 @babel/plugin-proposal-decorators)时,可用装饰器语法让拦截逻辑更简洁、声明式。
- 装饰器本质仍是高阶函数,只是写法更直观
- 支持类方法、访问器、甚至整个类的拦截
示例(方法装饰器):
function Log(target, propertyKey, descriptor) {
const original = descriptor.value;
descriptor.value = function(...args) {
console.log(`[${propertyKey}] 开始`, args);
const result = original.apply(this, args);
console.log(`[${propertyKey}] 结束`, result);
return result;
};
}
<p>class Service {
@Log
getData() {
return [1, 2, 3];
}
}</p><p>new Service().getData(); // 自动带日志注意事项和边界情况
实际使用中要注意几个关键点:
-
this 绑定:包装函数时用
fn.call(this, ...args)或fn.apply(this, args)保持上下文 -
异步函数:若原函数返回 Promise,拦截器也应正确 await 并传递异常(
try/catch+throw) - 箭头函数无法被 Proxy 的 get 拦截到 this:因为箭头函数不绑定 this,要确保目标方法是普通函数
- 性能开销:高频调用的函数慎加复杂拦截,避免影响关键路径
本质上,JavaScript 的“拦截器”是手动构建的控制流增强机制,不是语言内置特性。选哪种方式取决于你的场景:单个函数用高阶函数,整块对象用 Proxy,团队统一规范且支持装饰器语法时可用 @ 语法 —— 目标始终是清晰、可维护地插入横切逻辑。

















