代码之家  ›  专栏  ›  技术社区  ›  davidsleeps

对象/函数帮助中的Javascript设置超时

  •  1
  • davidsleeps  · 技术社区  · 15 年前

    我对闭包不熟悉,对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 回复  |  直到 13 年前
        1
  •  2
  •   sth ACP    15 年前

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

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

    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;
        }
    }
    
        2
  •  2
  •   Community PPrice    7 年前

    您正在正确使用闭包。因为当setTimeout调用您的函数时,“this”将是“Window”对象,您必须创建一个闭包(通过将“this”分配给我来实现)并访问它。

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

    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();
    
        3
  •  0
  •   Alex    15 年前

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

    1. 使用封装,即不要只制作所有变量&公共职能。您在该对象上将doStuff方法作为public,这意味着任何人都可以调用它,而不仅仅是count方法。这也适用于计数、限制和输出。相反,它们应该传递给构造函数。

    2. 使引用对象“me”成为类的私有成员,这样就不会在方法中设置它。如果使用call或apply调用该方法,您现在的操作方式可能会有问题,因为该方法的上下文将发生更改。

    例如

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

      if(doStuff())设置超时(函数(){ 我。伯爵(); },1000);

    下面是我所有建议的代码

    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);
            }
        };
    }
    
        4
  •  0
  •   Matthew Crumley    15 年前

    我看不出它有什么真正的问题,但有一些事情我可能会解决。

    • 我会将outputId和limit指定为构造函数的参数。如果仍然希望使用默认值,可以检查参数是否未定义,或者传递选项对象。
    • me doStuff中的参数是冗余的,因为它始终与 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移到函数外部会略微减少重复的代码。