Javascript定时器/延迟函数内的this对象

3

我有一个方法,它是一个大的setInterval语句,并且需要从内部间隔访问拥有该方法的对象的this对象。我实现了一个简单的闭包,但它似乎不太优雅:

connect: function(to, rate, callback){
    var cthis = this,                             //set cthis to this,
    connectIntervalID = setInterval(function(){
        if(cthis.attemptConnect(to)){             //reference it here,
            clearInterval(connectIntervalID)
            cthis.startListening(10)              //here,
            callback && callback.apply(cthis, []) //and here
        }
    }, rate)
}

如果你想使用this而不是cthis,你也可以使用applycall来实现。

connect: function(to, rate, callback){
    var cthis = this,
    tempFunc = function(){
        if(this.attemptConnect(to)){                 
            clearInterval(connectIntervalID)
            this.startListening(10)              
            callback && callback.apply(this, []) 
         }
     }�       
     connectIntervalID = setInterval(function(){tempFunc.apply(cthis, [])}, rate)
 }

然而,这似乎更糟...

这就是 JavaScript,不管好坏。 - Jason McCreary
3个回答

2

使用.bind会让代码变得更好(在我看来,你可能同意也可能不同意):

支持代码:

function $A(args){
   var out = [];
   for(var i=0, l=args.length; i<l; i++){ out.push(args[i]); }
   return out;
}

Function.prototype.bind = function() {
   var __method = this, args = $A(arguments), object = args.shift();

   return function() {
      return __method.apply(object || this, args.concat( $A(arguments) ));
   };
};

你的代码变成了:

connect: function(to, rate, callback){
    connectIntervalID = setInterval((function(){
        if(this.attemptConnect(to)){             //reference it here,
            clearInterval(connectIntervalID)
            this.startListening(10)              //here,
            callback && callback.apply(this, []) //and here
        }
    }).bind(this), rate)
}

但我担心你不会有太大的改善。

MDC指出,真正的ES5绑定方法在行为上确实有所偏差 - 您需要在ES5和非ES5浏览器中进行测试。https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind#Compatibility - PleaseStand

0
我会将 setInterval 函数分离到自己的函数中,并附加到与 connect 相同的对象上。这样就可以清楚地表明 this 指的是相同的对象:
connect: function (to, rate, callback) {
    var obj = this;
    var intervalId = setInterval(function () {
        obj.connectInterval(intervalId, callback);
    }, rate);
},
connectInterval: function (intervalId, callback) {
    if (this.attemptConnect(to)) {
        clearInterval(intervalId);
        this.startListening(10);
        callback && callback.apply(this, []);
    }
}

0

你的第一个例子基本上是实现这个功能的标准方式。我的唯一建议是将变量命名为除了cthis之外的其他描述性名称,以便更好地描述绑定的对象。

Javascript 1.8.5 添加了Function.prototype.bind来以不同的方式解决这个问题,但对于大多数人来说,这并不是一个有用的解决方案。


为什么bind对大多数人来说不是一个有用的解决方案?当它不存在时,进行特性检测并添加它是微不足道的。 - theazureshadow
@theazureshadow 这很有用,但只有在您需要重复使用时才有用。对于一次性使用,特征检测和支持代码不值得。 - David Tang
@Box9:我理解你的想法,但我认为很多人会觉得在正常使用中提高可读性是值得的(特别是如果他们在多个项目中使用它,每当需要时)。这是工具箱中有用的工具,因为它描述了闭包而不是将其隐含(更不用说潜在的意外) 。 - theazureshadow
它是1.8.5版本,只在最新的Firefox浏览器中可用。我使用Chrome 12进行开发,该浏览器只支持1.6或1.7版本,但除此之外,它应该可以正常工作。 - invisible bob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接