'装饰器函数内设置的对象属性未按预期持续存在'

问题描述

我才学习使用 JavaScript 4 个月,所以如果有什么明显我遗漏的地方,请告诉我。

在这个问题中,我写了两个函数

  • 一个是内部(非关键)工作职能。它只是添加了 2 个数字。
  • 第二个是装饰器函数,需要将work函数的参数存储到work本身的函数对象属性中,如work.calls = [ [[num1,num2],[etc,etc] ];
  • 根据问题的设置,定义后需要这样调用函数
work = spy(work);
work(1,2);
work.calls; // => [1,2]

我遵循了本文 Function Object 的“自定义属性”部分。因此,我希望函数对象属性 (work.calls) 在调用 spy(work) 后保留在工作对象中。

当我在调试器下运行代码时,得到了一个奇怪的结果。

  • work.calls 定义在 spy 函数的块内
  • work.calls 在 work(1,2) 中变得未定义

我尝试的解决方案如下所示:

function work(num1,num2) {
  return num1 + num2;
}

function spy(target) {
  target.calls = [];
  //set work.calls,work.calls is currently existing in debugger.
  
  function wrap(x,y) {
   
    target.calls.push([x,y]);
    
    return target(x,y);
  };
  
  
  return wrap
}

work = spy(work);

work(1,2);
work.calls; // => Now undefined in the debugger!

我发现的另一个解决方案建议将 target.calls 更改为 wrap.calls,它解决了问题。那么这是否意味着函数对象属性不是持久化的,除非从它们自己的主体内部创建?

function spy(target) {
  
  
  function wrap(x,y) {
   
    wrap.calls.push([x,y]);
    //using wrap instead of target allows work.calls to be persistent 
    
    return target(x,y);
  };
  
  wrap.calls = [];
  
  return wrap
}

work = spy(work);

work(1,2);

work.calls; // => [1,2] all good in work.calls... but why?

我不明白为什么设置 wrap.calls 允许该属性持续存在。对象在全球范围内不是总是持久的吗?

非常感谢您的耐心等待。我只是希望有人能帮助我理解这一点。

解决方法

我建议首先避免 work = spy(work);。而是写

const spiedWork = spy(work); ……

然后比较调用 work(1,2) 和调用 spiedWork(1,2) 时发生的情况。还要比较 spiedWork.callswork.calls。一旦弄清楚了这一点(以及那个 spiedWork !== work),您就会明白原始代码中发生了什么。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...