函数劫持是用新函数替换原函数并保留其功能,关键在于正确保存原函数引用、透传this与参数、记录日志,并支持同步/异步场景及错误捕获。

函数劫持本质是用新函数替换原函数,同时保留原函数功能并插入日志逻辑。关键在于正确保存原函数引用、调用原函数并捕获其返回值,避免丢失 this 和参数上下文。
保存原函数并封装新逻辑
先缓存原始函数,再定义包装函数,在执行前后插入日志。需用 apply 或 call 保证 this 和参数透传:
- 用闭包或变量保存原始函数引用,防止被覆盖后无法调用
- 新函数接收任意参数(...args),通过 func.apply(this, args) 调用原函数
- 记录函数名、入参、执行时间、返回值或异常,便于调试和监控
处理 this 绑定与箭头函数限制
普通函数劫持依赖 this 的动态绑定,但箭头函数不绑定 this,无法通过 this 访问调用上下文。因此:
- 劫持对象方法时,必须在目标对象上操作(如 obj.method = hijack(obj.method))
- 避免对箭头函数直接劫持——它没有自己的 this,也不可被 new 调用,通常应劫持其外层普通函数
- 若需统一处理,可用 Function.prototype.bind 显式绑定 this,再包装
支持异步函数与 Promise 拦截
对 async 函数或返回 Promise 的函数,日志需等待异步完成后再记录结果:
立即学习“Java免费学习笔记(深入)”;
- 判断返回值是否为 Promise:用 returnVal instanceof Promise
- 如果是,则用 .then().catch() 捕获成功/失败结果,并记录耗时与状态
- 同步函数直接记录返回值;异步函数统一返回原 Promise,保持调用链不变
实际应用示例(劫持 console.log)
以重写 console.log 为例,既保留原有输出,又添加时间戳和调用栈:
- 缓存原函数:const originalLog = console.log.bind(console)
- 重写:console.log = function(...args) { console.timeStamp('LOG'); originalLog(...args); }
- 注意使用 bind(console) 防止丢失 console 上下文,否则 originalLog 调用会报错
不复杂但容易忽略细节:this 绑定、参数透传、异步等待、错误捕获——把这四点理清楚,日志拦截就稳了。


















