装饰器为什么无法修改类的方法参数?
我在用装饰器封装API请求时遇到了问题,给类方法加了装饰器想自动处理参数,但发现参数始终没被修改。
比如这个装饰器:
function apiLogger(target, name, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args) {
args[0] = { ...args[0], timestamp: Date.now() }; // 想给第一个参数加时间戳
console.log('调用前参数:', args);
return originalMethod.apply(this, args);
};
return descriptor;
}
用在类方法里:
class Service {
@apiLogger
fetchData(params) {
console.log('实际接收到的params:', params);
return fetch(...);
}
}
调用service.fetchData({ id: 1 })时,控制台显示调用前参数确实有timestamp,但实际接收到的params里却没有这个字段,这是为什么?
改成这样:
function apiLogger(target, name, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args) {
const newParams = { ...args[0], timestamp: Date.now() };
console.log('调用前参数:', newParams);
return originalMethod.call(this, newParams);
};
return descriptor;
}
class Service {
@apiLogger
fetchData(params) {
console.log('实际接收到的params:', params);
return fetch(...);
}
}
你在装饰器中执行了
args[0] = { ...args[0], timestamp: Date.now() };,这一步是创建了一个新的对象,并将这个新对象赋值给了 args[0],但原对象本身的内容并没有被修改。也就是说,你只是让 args[0] 指向了一个新对象,而类方法内部接收到的 params 仍然是原始传入的那个对象。举个例子:
你调用时传的是一个对象
{ id: 1 },你在装饰器里把它替换成{ id: 1, timestamp: 123 },但原对象本身并没有被改动。你只是改变了参数的引用,而类方法里接收的就是那个原始对象,所以你加的 timestamp 并不会出现在 params 里。要解决这个问题,你可以直接修改原始对象,而不是替换它。比如:
这样,不管谁持有这个对象的引用,都能看到你加的 timestamp 字段。