【问题标题】:javascript setTimeout() first argument: expression errorjavascript setTimeout() 第一个参数:表达式错误
【发布时间】:2010-04-09 01:45:06
【问题描述】:
function Timer() {
 this.initialTime = 0;
 this.timeStart = null;

 this.getTotalTime = function() {
  timeEnd = new Date();
  diff = timeEnd.getTime() - this.timeStart.getTime();

  return diff+this.initialTime;
 };

 this.formatTime = function() {
  interval = new Date(this.getTotalTime());

  return  interval.getHours() + ":" +  interval.getMinutes() + ":" + interval.getSeconds();
 };

 this.start = function() {
  this.timeStart = new Date();

  setTimeout("this.updateTime()", 1000);
 };

 this.updateTime = function() {
  alert(this.formatTime());
  setTimeout("this.updateTime()", 1000);
 };
}


timer = new Timer();
timer.start();

我收到一个错误:

this.updateTime 不是函数

有什么想法吗?

谢谢

【问题讨论】:

  • 我想知道我们是否可以/应该将这个问题改成一个非常通用的问题。问题中的所有代码都没有帮助我,我只是直接回答:)。
  • 原来,setTimeout 以字符串作为其第一个参数的行为类似于 间接 eval。

标签: javascript time settimeout


【解决方案1】:

您的字符串不会在您的对象的上下文中进行评估,因此this 并不是指您认为的内容。

您不应将字符串参数传递给setTimeout。相反,您应该传递一个匿名函数,该函数使用已保存的 this 副本调用您的方法。

例如:

var self = this;
setTimeout(function() { self.updateTime(); }, 1000);

self 变量是必需的,因为 setTimeout 的回调也不会在您的对象的上下文中进行评估。

【讨论】:

  • 这行得通但是..有没有更优雅的方法?不定义全局变量?
  • 这是本地的,而不是全局的。您可以使用代理功能。
  • 好吧..无论如何我都不是 JS 专家。谢谢!
  • self 是一个常规的局部变量。因为匿名函数在同一范围内,所以它保存了对所有局部变量的引用。这是一个非常强大的功能,称为闭包。
  • 实际上,如果在updateTime函数内部定义self,也不能保证引用Timer对象。您的代码和直接setTimeout(this.updateTime) 之间没有区别。 this/self 具有相同的上下文。 :)
【解决方案2】:

试试

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

【讨论】:

    【解决方案3】:

    有没有更优雅的方式?

    是的,在 ECMAScript 第五版中:

    setTimeout(this.updateTime.bind(this), 1000);
    

    但是,在所有浏览器都支持第五版之前(它们还没有长期支持),您应该添加自己的 Function.bind 实现作为后备。例如:

    // Add ECMA262-5 method binding if not supported natively
    //
    if (!('bind' in Function.prototype)) {
        Function.prototype.bind= function(owner) {
            var that= this;
            if (arguments.length<=1) {
                return function() {
                    return that.apply(owner, arguments);
                };
            } else {
                var args= Array.prototype.slice.call(arguments, 1);
                return function() {
                    return that.apply(owner, arguments.length===0? args : args.concat(Array.prototype.slice.call(arguments)));
                };
            }
        };
    }
    

    您可能还喜欢使用setInterval 来避免重复的setTimeout 调用。最后,您应该记住将所有变量(timeEnddiff 等)声明为 var,否则您会意外获得全局变量,这可能会导致您在调试时心痛。

    【讨论】:

      【解决方案4】:

      如果您向setTimeout 提供一个字符串,该字符串将按字面意思执行。问题是,它将在稍后的某个时间在全局上下文中执行,在您的 Timer 对象之外,所以 this 意味着完全不同的东西。

      只需像这样传递函数本身:

      function Timer() {
        var self = this;   // make reference to this that won't change with context
      
        this.updateTime = function() {
          alert(self.formatTime());
          setTimeout(self.updateTime, 1000);
        };
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-12-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-16
        • 2015-06-09
        • 1970-01-01
        相关资源
        最近更新 更多