SetTimeout() внутри класса JavaScript с использованием "this"
Я пытаюсь использовать setTimeout()
внутри функции класса в JavaScript. Предполагается, что setTimeout()
запускает другой метод в одном классе, поэтому передаваемая мной функция записывается как window.setTimeout("this.anotherMethod", 4000)
. Это приводит к проблеме: this
ссылается на вызывающий объект, в случае setTimeout()
это window
. Как я могу использовать оболочки для возврата ссылки на объект класса?
myObject = function(){
this.move = function(){
alert(this + " is running");
}
this.turn = function(){
alert(this + " is turning");
}
this.wait = function(){
window.setTimeout("this.run" ,(1000 * randomNumber(1,5)));
}
this.run = function(){
switch(randomNumber(0,2)){
case 0:
this.move();
break;
case 1:
this.turn();
break;
case 2:
this.wait();
}
}
}
Ответы
Ответ 1
Вы можете сделать это:
var that = this;
setTimeout(function () {
that.doStuff();
}, 4000);
Вы также можете bind
для более сжатого кода (как первоначально указывал @Raynos):
setTimeout(this.doStuff.bind(this), 4000);
bind
- стандартная библиотечная функция для именно этого шаблона кодирования (т.е. захват this
лексически).
Ответ 2
Вы также можете привязать функцию к области видимости.
setTimeout(this.run.bind(this) ,(1000 * randomNumber(1,5)));
Предупреждение Function.prototype.bind
- ES5
Ответ 3
this
может быть проблематичным в javascript, как вы обнаружили.
Я обычно обходим это путем сглаживания this
внутри объекта, чтобы я мог использовать псевдоним всякий раз, когда мне нужна ссылка обратно на содержащий объект.
MyObject = function ()
{
var self = this;
// The rest of the code goes here
self.wait = function(){
window.setTimeout(self.run ,(1000 * randomNumber(1,5)));
}
}
Ответ 4
this.wait = function(){
var self = this;
window.setTimeout(function() { self.run() } ,(1000 * randomNumber(1,5)));
}
Итак, вы сохраняете ссылку на объект, который вы вызываете .run в локальной переменной ( "self" ).
Ответ 5
this
чувствителен к контексту, в котором он вызван. Когда вы передаете строку в setTimeout
, то это eval
ed в совершенно другом контексте.
Вам нужно сохранить текущее значение this
(путем копирования его на другую переменную) и сохранить область (не используя (подразумеваемые) eval
).
this.wait = function(){
var self = this;
setTimeout(function () { self.run() },
(1000 * randomNumber(1,5))
);
}
Ответ 6
В верхней части основного myObject
сделайте новую ссылку на текущее значение this
:
var self = this;
а затем создайте закрытие для обратного вызова по таймеру, которое использует эту новую ссылку вместо глобального объекта, который setTimeout
будет использовать в качестве контекста по умолчанию в обратных вызовах:
setTimeout(function() {
self.run();
}, 4000);
Ответ 7
var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);
внутри func
, this
всегда ссылаются на глобальный объект. вы можете передать текущий объект в func,
var timeoutID = window.setTimeout(func, delay, this);
function func(that) {...}
К сожалению, он НЕ работает в IE
Обратите внимание, что передача дополнительных параметров функции в первом синтаксисе не работает в Internet Explorer.
Ответ 8
Вы пробовали:
window.setTimeout("myObject.run" ,(1000 * randomNumber(1,5)));
Ответ 9
Вы можете просто использовать синтаксис функции стрелки:
setTimeout(() => {
this.doStuff();
}, 4000);
Ответ 10
Вместо этого вы можете использовать этот код, который работает во всех современных браузерах -
setTimeout(function(thisObj) {thisObj.run();},1000,this);
Ссылка: http://klevo.sk/javascript/javascripts-settimeout-and-how-to-use-it-with-your-methods/
Ответ 11
Более короткий путь. Без анонимной функции.
var self = this;
setTimeout(self.method, 1000);
Ответ 12
Не рекомендуется использовать setTimeout или setInterval с помощью строк
setTimeout("myFunction()", 5000);
//this is the same as
setTimeout(function(){ eval("myFunction()"); }, 5000)); //<-- eval == BAD
Ответ 13
Перейдите в более сложную ситуацию... класс A имеет член типа B и метод, который вызывает setTimeout, который вызывает метод класса B. Решается следующим образом:
class A {
constructor(b) {
this.b = b;
}
setTimer(interval) {
setTimeout(this.b.tick.bind(this.b), interval);
}
}
class B {
constructor(name){
this.name = name;
this.ele = window.document.getElementById('B');
}
tick() {
console.log(this);
this.ele.innerText += ' ' + this.name;
}
}
Какая привязка A.b к этому в B.tick и сработала.
Здесь сценарий с bind
: https://jsfiddle.net/jrme9hyh/
И один без bind
, который терпит неудачу: https://jsfiddle.net/2jde8tq3/