我试图将一个函数 work 传递给一个装饰器,它会将函数调用保存在一个数组 work.calls 中。

功能:

work(a, b) {
  console.log(a + b);
}

装饰师:
function decorator(func) {
  func.calls = [];
  return function(...args) {
    func.calls.push(args);
    return func.call(this, ...args);
  }
}

装饰函数 work :
work = decorator(work);

调用新函数:
work(1, 2); // 3
work(4, 5); // 9

for (let args of work.calls) {
  console.log( 'call:' + args.join() ); // TypeError: work.calls is not iterable
}
work.calls 是一个数组,为什么它不可迭代?

作为引用,其他人编写的另一个版本的装饰器实际上有效:
function decorator(func) {

  function wrapper(...args) {
    wrapper.calls.push(args);
    return func.apply(this, arguments);
  }

  wrapper.calls = [];

  return wrapper;
}

work(1, 2); // 3
work(4, 5); // 9

for (let args of work.calls) {
  alert( 'call:' + args.join() ); // "call:1,2", "call:4,5"
}
wrapper 在这里做什么以及为什么这种方式有效?

最佳答案

这两个功能的工作方式不同。您的装饰器在传递的函数上定义 calls 属性。另一个装饰器函数在嵌套和返回 ( wrapper ) 函数上设置属性。您会收到该错误,因为 work.callsundefined 。装饰的 work 指的是匿名函数:return function(...args),它没有 calls 属性。

如果您将 work = decorator(work); 更改为 let work2 = decorator(work); ,那么您将看到 calls 设置在原始 work 函数上,而不是 work2 上。

如果您在闭包的返回函数上定义 calls 属性,您的代码的工作方式相同。

function decorator(func) {
  function __(a, b) {
    __.calls.push([a, b])
    return func(a, b)
  }
  __.calls = []
  return __;
}

关于JavaScript:TypeError:work.calls 在函数装饰器中不可迭代(初学者问题),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52531907/

10-12 06:56