为什么 setTimeout 使用我的函数的旧版本?

Why does setTimeout use the old version of my function?

当我运行以下代码时:

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 生成一个新函数,因此 'locking' 在它的行为中。

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

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

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

在 3 中,您没有立即引用 fn - 您正在传递一个不同的匿名函数。只有当那个匿名函数 运行s 和它里面的行得到 运行 时,解释器才会检查这些行上的引用以查看变量名称指向什么值。

But in the 4th case, why doesn't setTimeout make use of the latest version of fn?

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

在第 3 种情况下,您有一个 包含 fn 的引用的函数,它将在匿名函数 运行 和口译员遇到了那条线——但之前没有。

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

摘要如下:

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

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

然后,

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

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

setTimeout(fn, 750);

上面你把第一个函数的引用给了setTimeout。它存储此引用并在 750ms

后执行