Why is an anonymous function required to preserve “this” using setTimeout

戏子无情 提交于 2019-12-22 04:30:14

问题


I've used setTimeout plenty of times passing a function as a reference e.g.

setTimeout(someFunction, 3000);

In some cases, to preserve the value of this I've had to assign it to a variable before hand, but don't understand why the following does not work:

var logger = {
    log: function() { 
        var that = this;
        console.log(that.msg); 
        setTimeout(that.log, 3000); 
    },
    msg: "test"
};

logger.log();

Using an anonymous function however, does work:

var logger = {
    log: function() { 
        var that = this;
        console.log(that.msg); 
        setTimeout(function() { that.log() }, 3000); 
    },
    msg: "test"
};

回答1:


This doesn't work as setTimeout calls a function with the this value as the global object, not the parent object. You're passing a value into the setTimeout function -- it doesn't know how it's been accessed, and therefore cannot call it with the correct this value (unlike normal variables, the value of this is only determined when you call the function, unless this has been bound to a specific value using Function.prototype.bind).

By changing that to an anonymous function, you're using the closure to access the value of that, even when called as a value (the variable scope of a function is set when it is defined, not when it is run).

It's just like if you do something like this:

var a = { b: function () { return this.foo; }, foo: 'proper' };
function test(arg) {
    return arg();
}
var foo = 'random';
console.log(a.b()); // proper
console.log(test(a.b)); // random

There's also a related question on using this with setTimeout: Pass correct "this" context to setTimeout callback?




回答2:


Because in the first case you reference only the function log that is within the that object, but its relationship to that is lost. Think of it as setTimeout calls directly the log method at the stored memory address with the global context.

In the second example however you come from a global context, but first that is looked up, and afterwards log which is called then with the context of that.

Think of setTimeout having the following structure:

var setTimeout = function (func, time) {
   someWaitMechanism(time, function () { //this is called after the timeout
       func.call(null); //calls func with global scope
   });
}


来源:https://stackoverflow.com/questions/21429255/why-is-an-anonymous-function-required-to-preserve-this-using-settimeout

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!