setTimeout и «это» в JavaScript - PullRequest
       40

setTimeout и «это» в JavaScript

31 голосов
/ 26 февраля 2009

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

например:

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];
        }
    }
};

Ответы [ 5 ]

48 голосов
/ 26 октября 2013

Более элегантный вариант - добавить .bind(this) в конец вашей функции. E.g.:

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

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

    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
    }; 
45 голосов
/ 26 февраля 2009

Проблема в том, что 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);
};

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

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

Также, как sidenote, вы настраиваете себя на бесконечный цикл, так как method() всегда вызывает method().

7 голосов
/ 26 февраля 2009

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

2 голосов
/ 08 февраля 2018

в es6 вы можете сделать это так

window.setTimeout(() => {
    this.foo();
}, 1000);   
0 голосов
/ 26 февраля 2009

Я получаю ошибку, которая говорит, что method2 не определен

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...