上下文迷路了

时间:2013-03-15 15:50:54

标签: javascript scope

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

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()

2 个答案:

答案 0 :(得分:1)

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

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时,你将它绑定到你的对象上。我仍然不确定我理解为什么你不喜欢这种技术,但它是一个有效的模式,许多lib等使用。

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

答案 1 :(得分: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) 
};