Как использовать «setTimeout» для вызова самого объекта - PullRequest
24 голосов
/ 09 июля 2009

Почему я не могу использовать setTimeout в объекте javascript?

Message = function () {

    ...
    ...        

    this.messageFactory = ...
    this.feedbackTag = document.getElementById('feedbackMessages');

    this.addInfo = function (message) {
        var info = this.messageFactory.createInfo(message); // create a div
        this.feedbackTag.appendChild(info);

        setTimeout('this.feedbackTag.removeChild(info)', 5000);
        // why in here, it complain this.feedbacktag is undefined ??????

    };
}

Спасибо за решение Стива, теперь оно будет работать, если код будет таким, как показано ниже ... поскольку «this» ранее фактически указывало на функцию в setTimeOut, оно не может перечитать Message.

Message = function () {

    ...
    ...        

    this.messageFactory = ...
    this.feedbackTag = document.getElementById('feedbackMessages');

    this.addInfo = function (message) {
        var info = this.messageFactory.createInfo(message); // create a div
        this.feedbackTag.appendChild(info);

        var _this = this;
        setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000);

    };
}

Но почему это не работает, если мы делаем это:

Message = function () {

    ...
    ...        

    this.messageFactory = ...
    this.feedbackTag = document.getElementById('feedbackMessages');
    // public function
    this.addInfo = function (message) {
        var info = this.messageFactory.createInfo(message); // create a div
        this.feedbackTag.appendChild(info);

        delayRemove(info);

    };
    // private function
    function delayRemove(obj) {
        var _this = this;
        setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000);
    }
}

Ответы [ 3 ]

84 голосов
/ 09 июля 2009

Попробуйте заменить эту строку:

setTimeout('this.feedbackTag.removeChild(info)', 5000);

с этими двумя строками:

var _this = this;
setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000);

Примечание:

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

Наконец, всегда проверяйте, что ключевое слово this указывает на то, на что, по вашему мнению, оно указывает (см. http://www.alistapart.com/articles/getoutbindingsituations).

Решение вопроса 2:

Я считаю, что для нормальных функций this устанавливается для объекта window независимо от того, где они объявлены. Поэтому перемещение кода в отдельную функцию не решит проблему.

9 голосов
/ 16 марта 2011

Более точный способ - просто передать this в качестве аргумента функции, вызываемой во время ожидания:

function delayRemove(obj) {
  setTimeout(function(_this) {
      _this.feedbackTag.removeChild(obj);
    }, 5000, this);
}

Вы также должны передать obj в качестве аргумента, просто чтобы убедиться, что он находится в области видимости (количество параметров не ограничено):

function delayRemove(obj) {
  setTimeout(function(_this, removeObj) {
      _this.feedbackTag.removeChild(removeObj);
    }, 5000, this, obj);
}

HTML5 и Node.js расширили функцию setTimeout, чтобы принимать параметры, которые передаются вашей функции обратного вызова. Он имеет следующую сигнатуру метода.

setTimeout(callback, delay, [param1, param2, ...])

Поскольку setTimeout на самом деле не является функцией JavaScript ваши результаты могут отличаться в разных браузерах. Я не смог найти какие-либо конкретные детали поддержки, однако, как я уже сказал, это в спецификации HTML5.

2 голосов
/ 01 декабря 2010

Чтобы ответить на ваш последний вопрос: «Почему это не работает, если мы делаем это»:

Message = function () {

...
...        

this.messageFactory = ...
this.feedbackTag = document.getElementById('feedbackMessages');
// public function
this.addInfo = function (message) {
    var info = this.messageFactory.createInfo(message); // create a div
    this.feedbackTag.appendChild(info);

    delayRemove(info);

};
// private function
function delayRemove(obj) {
    var _this = this;
    setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000);
}}

Это не работает, потому что вы передаете неопределенную переменную (info) вместо определенной переменной (obj). Вот исправленная функция:

function delayRemove(obj) {
var _this = this;
setTimeout(function() { _this.feedbackTag.removeChild(obj); }, 5000);}
...