javascript setTimeout () первый аргумент: ошибка выражения - PullRequest
1 голос
/ 09 апреля 2010
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 не является функцией

Есть идеи?

Спасибо

Ответы [ 4 ]

2 голосов
/ 09 апреля 2010

Ваша строка не оценивается в контексте вашего объекта, поэтому this не относится к тому, что вы думаете, что он делает.

Вы не должны передавать строковый аргумент setTimeout. Вместо этого вы должны передать анонимную функцию, которая вызывает ваш метод с сохраненной копией this.

Например:

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

Переменная self необходима, потому что обратный вызов setTimeout также не оценивается в контексте вашего объекта.

1 голос
/ 09 апреля 2010

есть ли более элегантный способ?

Да, в пятом издании ECMAScript:

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

Однако до тех пор, пока все браузеры не будут поддерживать Пятое издание (что пока еще не принято), вы должны добавить свою собственную реализацию Function.bind в качестве запасного варианта. eg.:

// 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. Наконец, вы должны помнить, что все ваши переменные (timeEnd, diff и т. Д.) Должны быть объявлены как var, в противном случае вы получаете случайные глобальные переменные, которые могут вызвать ужасную отладочную боль в сердце.

1 голос
/ 09 апреля 2010

1001 * попробовать *

var me = this;
setTimeout(function() { me.updateTime() }, 1000);
0 голосов
/ 09 апреля 2010

Если вы введете строку для 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);
  };

}
...