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];
}
}
};
Ответы
Ответ 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.