装饰器为什么无法修改类的方法参数?

夏侯雯清 阅读 30

我在用装饰器封装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里却没有这个字段,这是为什么?

我来解答 赞 7 收藏
二维码
手机扫码查看
2 条解答
Tr° 馨冉
问题出在参数是按值传递的,你改的是args数组里的值,但原方法接收的是原始对象引用。直接改方法签名接收新对象就行。

改成这样:

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(...);
}
}
点赞
2026-02-20 07:00
博主乙涵
这个问题的核心在于你修改了参数的引用,但类方法内部接收的仍然是原始对象的引用。

你在装饰器中执行了 args[0] = { ...args[0], timestamp: Date.now() };,这一步是创建了一个新的对象,并将这个新对象赋值给了 args[0],但原对象本身的内容并没有被修改。也就是说,你只是让 args[0] 指向了一个新对象,而类方法内部接收到的 params 仍然是原始传入的那个对象。

举个例子:
你调用时传的是一个对象 { id: 1 },你在装饰器里把它替换成 { id: 1, timestamp: 123 },但原对象本身并没有被改动。你只是改变了参数的引用,而类方法里接收的就是那个原始对象,所以你加的 timestamp 并不会出现在 params 里。

要解决这个问题,你可以直接修改原始对象,而不是替换它。比如:

function apiLogger(target, name, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args) {
args[0].timestamp = Date.now(); // 直接修改原始对象
console.log('调用前参数:', args);
return originalMethod.apply(this, args);
};
return descriptor;
}


这样,不管谁持有这个对象的引用,都能看到你加的 timestamp 字段。
点赞 6
2026-02-05 17:02