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

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();
    }
}

}

4b9b3361

Ответ 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);

Ответ 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/