对象/函数帮助中的Javascript setTimeout

时间:2009-07-24 03:26:08

标签: javascript closures

我是封闭式的新手,并且有一个'让我做大多数事情'对javascript的理解,所以我想知道我如何改进以下是我试图拥有一个具有计数器的对象。试图改善/进一步理解。

编辑:以下代码有效,当然......但可能是错误的(是吗?)......我甚至都不知道代码是正确还是错误......我在哪里可以改进......有没有更好的方法在对象/函数中有一个计时器?

function myObj() {
    this.outputId = 'div_output1';
    this.counter = 0;
    this.limit = 10;
    this.count = function() {
        // reference to self
        var me = this;

        if (me.doStuff(me)) setTimeout(function() {
            me.count();
        },1000);
    };
    this.doStuff = function(me) {
        if (me.counter >= me.limit) {
            document.getElementById(me.outputId).innerText = 'count reached limit';
            return false;

        } else {
            document.getElementById(me.outputId).innerText = 'count = ' + me.counter;
            me.counter += 1;
            return true;
        }
    }
}

//对象的示例用法......

window.onload = function() {

    var x = new myObj;
    x.outputId = 'div_output2';
    x.count();

    var y = new myObj;
    y.limit = 8;
    y.count();
}

4 个答案:

答案 0 :(得分:2)

我会在this上使用闭包仅用于回调函数中的函数调用。对象的其他方法可以像往常一样使用this。回调需要显式引用该对象,因为它需要“从外部”调用对象方法。但对于被调用的方法,它只是一个普通的函数调用,它可以像往常一样使用隐式this来访问它的对象。

我通常也会将方法声明从构造函数中移到对象原型中,因为它更清晰,更有效:

function myObj() {
    this.outputId = 'div_output1';
    this.counter = 0;
    this.limit = 10;
}

myObj.prototype.count = function() {
    // reference to self
    var me = this;
    var callback = function() {
        me.count();
    };

    if (this.doStuff())
        setTimeout(callback,1000);
}

myObj.prototype.doStuff = function() {
    if (this.counter >= this.limit) {
            document.getElementById(this.outputId).innerText = 'count reached limit';
            return false;

    } else {
            document.getElementById(this.outputId).innerText = 'count = ' + this.counter;
            this.counter += 1;
            return true;
    }
}

答案 1 :(得分:2)

您正在使用关闭。因为当setTimeout调用你的函数时,'this'将是'Window'对象,你必须创建一个闭包(你通过将'this'赋给我)并访问它。

无论如何,我仍然会以不同的方式编写代码。我会让doStuff调用自己,而不是让它返回true / false然后决定是否再次调用doStuff。

我不喜欢你如何将'this'对象传递给this.doStuff函数。没有必要这样做。要了解“此”在JavaScript中的工作原理,请查看my detailed answer on the subject

function Counter(opts)
{
    this.outputId = opts.outputId || 'div_output1';
    this._currentCount = 0;
    this.limit = opts.limit || 10;

    this.count = function()
                 {                          
                    this.deferDoStuff();
                 };

    this.deferDoStuff = function()
                 {
                     var me = this;
                     setTimeout(function() { me.doStuff(); }, 1000);
                 };

    this.doStuff = function()
                   {
                        if(this._currentCount > this.limit)
                        {
                            document.getElementById(this.outputId).innerHTML = 'Count limit reached';
                            return;
                        }

                        document.getElementById(this.outputId).innerHTML = 'count = ' + this._currentCount;
                        this._currentCount++;
                        this.deferDoStuff();
                   };
}

用法:

        var x = new Counter( { 'outputId' : 'div1' } );
        var y = new Counter( { 'outputId' : 'div2' } );

        x.count();
        y.count();

答案 2 :(得分:0)

我清理代码的一些方法是:

  1. 使用封装,即不要只是制作所有变量&功能公开。你有doStuff方法作为公共对象,这意味着任何人都可以调用,而不仅仅是count方法。这也适用于count,limit和outputId。相反,它们应该传递给构造函数。

  2. 使引用对象“me”成为类的私有成员,因此不要在方法中设置它。如果您使用call或apply调用方法,则可能会出现问题,因为此上下文已更改。

  3. e.g。

    var obj = new myObj();
    var otherobj = {};
    obj.call.call(otherobj);
    
    1. 如果你有计数,我也会更改内联。你只是在寻找麻烦!!!

      if(doStuff())setTimeout(function(){     me.count(); },1000);

    2. 以下是包含我所有建议的代码

      function myObj(outputId, limit) {
          var counter = 0,
              me = this;
      
          function doStuff() {
              if (counter >= limit) {
                      document.getElementById(outputId).innerText = 'count reached limit';
                      return false;
      
              } else {
                      document.getElementById(outputId).innerText = 'count = ' + counter;
                      counter += 1;
                      return true;
              }
          }
          this.count = function() {
              if (doStuff()) {
                  setTimeout(function() {
                      me.count();
                  },1000);
              }
          };
      }
      

答案 3 :(得分:0)

我没有看到任何真正的问题,但我可能会清理一些事情。

  • 我会指定outputId和limit作为构造函数的参数。如果您仍希望拥有默认值,则可以检查未定义的参数,或传递选项对象。
  • doStuff中的me参数是多余的,因为它始终与this相同,并且您不需要在闭包中捕获它。
  • 我可能会写这样的doStuff:

    var outputDiv = document.getElementById(this.outputId);
    this.doStuff = function() {
        this.counter++;
        if (this.counter > this.limit) {
            outputDiv.innerText = 'count reached limit';
            return false;
        }
        else {
            outputDiv.innerText = 'count = ' + this.counter;
            return true;
        }
    }
    

    这是一个次要的风格,但我认为更明显的是doStuff正在修改计数器,因为它位于函数的开头而不是隐藏在else子句中。此外,在函数外部移动getElementById可以略微减少重复的代码。