【问题标题】:Why does setTimeout use the old version of my function?为什么 setTimeout 使用我的函数的旧版本?
【发布时间】:2021-08-03 09:59:12
【问题描述】:

当我运行以下代码时:

let fn = () => console.log('original fn was called');
fn();
setTimeout(fn.bind(this), 250);
setTimeout(() => fn(), 500);
setTimeout(fn, 750);
fn = () => console.log('updated fn was called');

这是输出:

original fn was called
original fn was called
updated fn was called
original fn was called

我直观地理解为什么输出前两行:

  1. 立即调用该函数。
  2. bind 方法从fn 生成一个新函数,因此“锁定”了它的行为。

但是,我对为什么第 3 行和第 4 行不同感到困惑。我想在第三种情况下,在调用包装匿名函数之前,不会评估对 fn 的引用。因此,它将利用 fn 的更新实现是有道理的。但是第4种情况,为什么setTimeout不使用最新版的fn呢?

【问题讨论】:

  • 闭包按名称进行延迟查找,其余部分急切地引用原始函数对象

标签: javascript settimeout pass-by-reference


【解决方案1】:

总结如下:

let fn = () => console.log('original fn was called');
fn = () => console.log('updated fn was called');

执行上述操作时,您会在内存中创建两个不同的函数。但是 - 通过第二个语句,您将丢失指向第一个函数的任何引用。

那么,

setTimeout(() => fn(), 500);

.. 你说在 500 毫秒后执行 fn 引用的任何内容。此时,引用指向代码中的“更新”函数。

setTimeout(fn, 750);

通过上面您将第一个函数的引用提供给 setTimeout。它存储此引用并在 750 毫秒后执行

【讨论】:

    【解决方案2】:

    “fn”只是对对象的引用:首先是“原始”函数;最后是“更新”功能。在第三种情况下,setTimeout 调用 ()=>fn,到那时 fn 具有“更新”值,但在第四种情况下,“原始”对象被传递给 setTimeout...

    【讨论】:

      【解决方案3】:

      只有在解释器运行语句时才会评估变量引用。在 1、2 和 4 中,您立即引用 fn,并以某种方式使用它传递给 setTimeout

      fn();
      setTimeout(fn.bind(this), 250);
      setTimeout(fn, 750);
      

      在 3 中,您没有立即引用 fn - 您正在传递一个不同的匿名函数。只有当该匿名函数运行并且其中的行运行时,解释器才会检查这些行上的引用以查看变量名称指向的值。

      但是在第4种情况下,为什么setTimeout不使用最新版本的fn呢?

      因为您在调用setTimeout 时直接引用了fn,就像在情况1 和2 中一样。

      在第三种情况下,您有一个包含fn 的引用的函数,它将在匿名函数运行并且解释器遇到该行时进行评估 - 但不是在此之前。

      【讨论】:

      • 我想我开始明白了,谢谢。所以基本上,在 #4 的情况下,fn 会立即被 setTimeout 取消引用?也就是说,setTimeout 函数并没有保持引用 750 毫秒。相反,它会立即将其“交换”为函数对象本身?
      • 这是看待它的一种方式。变量名不传递给函数 - 普通值 传递给函数。
      猜你喜欢
      • 1970-01-01
      • 2013-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-22
      • 2017-03-08
      • 1970-01-01
      相关资源
      最近更新 更多