Подтвердить что ты не робот

SetTimeout и "this" в JavaScript

У меня есть метод, который использует функцию setTimeout и вызывает вызов другого метода. При начальной загрузке метод 2 работает нормально. Однако после таймаута я получаю сообщение об ошибке method2 undefined. Что я здесь делаю неправильно?

Пример:

test.prototype.method = function()
{
    //method2 returns image based on the id passed
    this.method2('useSomeElement').src = "http://www.some.url";
    timeDelay = window.setTimeout(this.method, 5000);
};

test.prototype.method2 = function(name) {
    for (var i = 0; i < document.images.length; i++) {
        if (document.images[i].id.indexOf(name) > 1) {
            return document.images[i];
        }
    }
};
4b9b3361

Ответ 1

Проблема заключается в том, что setTimeout() заставляет javascript использовать глобальную область видимости. По сути, вы вызываете класс method(), но не из "this". Вместо этого вы просто указываете setTimeout на использование функции "method", без какой-либо конкретной области.

Чтобы исправить это, вы можете обернуть вызов функции в другой вызов функции, который ссылается на правильные переменные. Он будет выглядеть примерно так:

test.protoype.method = function()
{
    var that = this;

    //method2 returns image based on the id passed
    this.method2('useSomeElement').src = "http://www.some.url";

    var callMethod = function()
    {
        that.method();
    }

    timeDelay = window.setTimeout(callMethod, 5000);
};

", который может быть "this", потому что callMethod() находится в пределах области действия.

Эта проблема становится более сложной, когда вам нужно передать параметры методу setTimeout, поскольку IE не поддерживает более двух параметров для setTimeout. В этом случае вам нужно будет прочитать closures.

Кроме того, в качестве побочного элемента вы настраиваете себя на бесконечный цикл, так как метод() всегда вызывает метод().

Ответ 2

Более элегантным вариантом является добавление .bind(this) в конец вашей функции. Например:.

    setTimeout(function() {
        this.foo();
    }.bind(this), 1000);
//   ^^^^^^^^^^^ <- fix context

Таким образом, ответ на вопрос OP может быть:

    test.prototype.method = function()
    {
        //method2 returns image based on the id passed
        this.method2('useSomeElement').src = "http://www.some.url";
        timeDelay = window.setTimeout(this.method.bind(this), 5000);
        //                                       ^^^^^^^^^^^ <- fix context
    }; 

Ответ 3

"this", который вы использовали в setTimeOut, просматривается через себя. Создайте var "foo = this;" внутри вашей функции test.prototype.method и вместо этого используйте foo.

Ответ 4

Я получаю сообщение об ошибке, которое говорит, что метод2 undefined

Да, когда вы отбрасываете "this.method" у своего владельца и передаете только функцию setTimeout, вы теряете ассоциацию, которая устанавливает "это", поэтому "this в методе() равно окну глобального объекта".

См. этот ответ для объяснения удивительного способа" это действительно работает в JavaScript.