0

当我没有在回调中绑定“this”时,为什么我会丢失 setTimeout 的上下文。
在下面的代码中,您可以看到 onTime 在 3 个地方被调用。
一次从班里出来。哪个工作正常。
一次从课外。哪个工作正常。
当计时器触发呼叫时。“this”需要绑定方法。
有没有办法在每次回调中不使用绑定来强制上下文?

var MyBaseClass = function () {
    "use strict";
    this._base = {};
    this._base.baseFunc = function () {
        console.log('baseFunc called')
    };
    return this._base;
};

var TestClass =  function () {
    "use strict";
    if (TestClass.prototype._singletonInstance) {
        return TestClass.prototype._singletonInstance;
    }
    TestClass.prototype._singletonInstance = this;
    this._timer = {};
    console.log('constructor')
};
TestClass.prototype = new MyBaseClass();        // Set prototype to MyBaseClass
TestClass.prototype.constructor = TestClass;   // Set constructor back to TestClass

TestClass.prototype.onTime = function () {
    "use strict";
    console.log('ontime called')
    console.log(this, "<--- why do i lose context")
    this.baseFunc()
}
TestClass.prototype.init = function () {
    "use strict";
    console.log('local')
    this.onTime()
    //this._timer = setTimeout(this.onTime.bind(this),500)// works
    this._timer = setTimeout(this.onTime, 500) // no work
};

var asdf = new TestClass()
asdf.init()
console.log('global')
asdf.onTime()
4

2 回答 2

1

请注意,您只将一个函数传递给 setTimeout,而不是一个对象,因此 setTimeout 不可能知道您想要的上下文。解决方案是使用包装函数来保存上下文(dojo 的障碍,在许多其他库中称为绑定)。这强制上下文的方法,我不确定你为什么要寻找其他东西。一种选择可能是在构造函数中绑定一次,然后您可以传递函数而不用担心上下文,如下所示:

this.onTime = this.onTime.bind(this); // now you can pass the function around this._timer = setTimeout(this.onTime, 500) // works

澄清并尝试处理您关于原型的问题......

您将在构造函数中绑定函数(这是我假设您的 init 函数将被用作)而不是其他任何地方的原因是,如果您构造(使用new)第二个对象,您希望该对象成为在其上执行的功能的上下文。直接执行函数时可以免费获得此行为 ( myObj.myFunc),但在传递函数时需要小心 (setTimeout(myObj.myFunc, 50)var callback = myObj.myFunc;)。这是您遇到的核心问题,您可以使用两种策略:

传递函数时绑定

这基本上是您自己开发的方法,当将您的函数传递给 时setTimeout,您将它绑定到您的对象。我仍然不确定我是否理解您为什么不喜欢这种技术,但它是许多库等使用的有效模式。

setTimeout(myObj.myFunc.bind(myObj), 50);

构造对象时绑定

这是您可以绑定的最快时间 - 在原型上设置函数时无法绑定,因为尚未构造对象,您将绑定到什么?使用这种技术,您可以正常调用 setTimeout,在知道您传递的函数已“预绑定”的情况下是安全的。

var myObjClass = function(){
    this.myFunc = this.myFunc.bind(this);
}
myObjClass.prototype.myFunc = function(){};
var myObj = new myObjClass();

setTimeout(myObj.myFunc);
于 2013-03-15T15:59:22.690 回答
0

JSFiddle

为了保持上下文,在 setTimeout 中创建一个新方法。您正在传递没有上下文关联的方法引用。

TestClass.prototype.init = function () {
    "use strict";
    console.log('local')
    this.onTime();
    var me = this; 
    //this._timer = setTimeout(this.onTime.bind(this),500)// works
    this._timer = setTimeout(function(){
        me.onTime();
        }, 500) 
};
于 2013-03-15T15:53:54.680 回答