JavaScript中为原型方法添加日志需拦截调用并插入日志逻辑,常用方式包括:1. Proxy代理构造函数间接实现;2. 直接重写原型方法(适合调试);3. 装饰器模式封装增强。

在 JavaScript 中,原型对象本身不自动记录方法调用日志,但你可以通过代理(Proxy)、方法重写(monkey patching)或封装构造函数等方式,为原型上的方法添加日志能力。核心思路是:**拦截对原型方法的访问或调用,插入日志逻辑后再执行原方法**。
用 Proxy 包裹原型对象(推荐,非侵入式)
Proxy 不能直接代理普通对象的原型(prototype 是普通对象,但无法被 Proxy 完全代理其所有行为,尤其涉及 new 和内部方法时),但可以代理「实例」或「构造函数」,间接实现日志。更实用的方式是:在创建实例前,用 Proxy 包裹构造函数,使其返回带日志能力的实例。
- 不修改原有原型,保持代码干净
- 日志逻辑与业务逻辑解耦
- 支持按需开启/关闭日志
示例:
function withLogging(ctor, methodNames = []) {
return new Proxy(ctor, {
construct(target, args) {
const instance = new target(...args);
methodNames.forEach(methodName => {
if (typeof instance[methodName] === 'function') {
const original = instance[methodName];
instance[methodName] = function(...args) {
console.log(`[LOG] ${methodName} called with`, args);
return original.apply(this, args);
};
}
});
return instance;
}
});
}
<p>// 原始类
class Calculator {
add(a, b) { return a + b; }
multiply(a, b) { return a * b; }
}</p><p>const LoggedCalc = withLogging(Calculator, ['add', 'multiply']);
const calc = new LoggedCalc();
calc.add(2, 3); // → [LOG] add called with [2, 3]
直接重写原型方法(简单直接,适合调试)
适用于临时调试或已知稳定接口的场景。直接在原型上保存原方法,再覆盖为带日志的新方法。
立即学习“Java免费学习笔记(深入)”;
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
- 改动小、见效快
- 注意避免重复包装(可加标记判断)
- 生产环境慎用,可能影响其他模块
示例:
// 仅对 Calculator.prototype.add 加日志
const originalAdd = Calculator.prototype.add;
Calculator.prototype.add = function(...args) {
console.log(`[PROTOTYPE LOG] Calculator.add(${args.join(', ')})`);
return originalAdd.apply(this, args);
};
用装饰器模式封装原型方法(ES6+,可复用)
定义一个通用的日志装饰器函数,用于增强任意方法,再批量应用到原型上。
- 逻辑复用性强,易测试
- 可扩展支持耗时统计、错误捕获等
- 适合中大型项目统一日志规范
示例:
function logCalls(methodName, fn) {
return function(...args) {
console.groupCollapsed(`▶ ${methodName}(${args.map(a => JSON.stringify(a)).join(', ')})`);
console.trace(); // 可选:打印调用栈
try {
const result = fn.apply(this, args);
console.log(`← returns:`, result);
console.groupEnd();
return result;
} catch (err) {
console.error(`✗ throws:`, err);
console.groupEnd();
throw err;
}
};
}
<p>// 批量增强
['add', 'multiply'].forEach(key => {
Calculator.prototype[key] = logCalls(key, Calculator.prototype[key]);
});
注意事项与边界情况
原型方法日志容易忽略的关键点:
-
this 绑定:确保日志包装后仍正确传递
this(使用apply或箭头函数需谨慎) -
getter/setter:Proxy 可拦截,但直接重写原型需分别处理
Object.defineProperty - 继承链:子类原型方法若未重写,日志需作用于父类原型,否则不生效
- 性能开销:高频调用方法加日志会影响性能,建议开发/测试环境启用,生产环境关闭

















