简体   繁体   中英

Why does setTimeout use the old version of my function?

When I run the following code:

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');

This is outputted:

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

I intuitively grok why the first two lines are outputted:

  1. The function is immediately called.
  2. The bind method is producing a new function from fn , therefore 'locking' in it's behavior.

However, I'm confused as to why lines 3 and 4 are different. I suppose in the 3rd case, the reference to fn is not being evaluated until the wrapping anonymous function is called. So it makes sense that it would utilize the updated implementation of fn . But in the 4th case, why doesn't setTimeout make use of the latest version of fn ?

A variable reference is evaluated only when the interpreter runs the statement. In 1, 2, and 4, you're referencing fn immediately, and using it somehow to pass to setTimeout :

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

In 3, you're not referencing fn immediately - you're passing in a different anonymous function. Only when that anonymous function runs and the lines inside it get run do the references on those lines get checked by the interpreter to see what value the variable name points to.

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

Because you referenced fn directly when calling setTimeout , just like in cases 1 and 2.

In the 3rd case, you have a function which contains a reference to fn , which will be evaluated when the anonymous function runs and the interpreter comes across that line - but not before.

The "fn" is just a reference to an object: first the "original" function; and in the end the "updated" function. In the third case the setTimeout called ()=>fn, and by that time fn had the "updated" value, but in the fourth case the "original" object was passed to setTimeout...

Here is the summary:

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

When doing the above, you create two distinct functions in the memory. But - by the second statement, you lose any reference pointing to the first function.

Then,

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

.. you say execute after 500ms whatever referenced by fn . By this time the reference points to the "updated" function in your code.

setTimeout(fn, 750);

By above you give the reference of the first function to setTimeout. It stores this reference and executes after 750ms

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM