web-dev-qa-db-ja.com

「this」を使用するJavaScriptクラス内のsetTimeout()

JavaScriptのクラス関数内でsetTimeout()を使用しようとしています。 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();
    }
}

}

41
Dean

あなたはこれを行うことができます:

 var that = this;
 setTimeout(function () {
     that.doStuff();
 }, 4000);

また、 bind より簡潔なコード(@Raynosによって最初に指摘されたように)を使用することもできます。

setTimeout(this.doStuff.bind(this), 4000);

bindは、まさにこのコーディングパターンの標準ライブラリ関数です(つまり、thisをレキシカルにキャプチャします)。

70
Tikhon Jelvis

関数をスコープにバインドすることもできます。

setTimeout(this.run.bind(this) ,(1000 * randomNumber(1,5)));

警告Function.prototype.bindはES5です

7
Raynos

あなたが発見したように、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)));
    }
}
6
GordonM
this.wait = function(){
    var self = this;
    window.setTimeout(function() { self.run() } ,(1000 * randomNumber(1,5)));
}

したがって、.runを呼び出すオブジェクトへの参照をローカル変数( 'self')に格納します。

3
Gijs

thisは、それが呼び出されるコンテキストに依存します。文字列をsetTimeoutに渡すと、完全に異なるコンテキストでevaledされます。

thisの現在の値を保持し(別の変数にコピーすることにより)、スコープを維持する必要があります(暗黙のevalを使用しないことにより)。

this.wait = function(){
    var self = this;
    setTimeout(function () { self.run() },
              (1000 * randomNumber(1,5))
              );
}
2
Quentin

メインmyObjectの上部で、thisの現在の値への新しい参照を作成します。

var self = this;

次に、setTimeoutがコールバックのデフォルトコンテキストとして使用するグローバルオブジェクトの代わりに、その新しい参照を使用するタイマーコールバックのクロージャーを作成します。

setTimeout(function() {
    self.run();
}, 4000);
2
Alnitak
var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);

内部functhisは常にグローバルオブジェクトを参照します。現在のオブジェクトをfuncに渡すことができます。

var timeoutID = window.setTimeout(func, delay, this);
function func(that) {...}

残念ながらIEでは機能しません

最初の構文で関数に追加のパラメーターを渡すことは、Internet Explorerでは機能しないことに注意してください。

2
nandin

やってみました;

window.setTimeout("myObject.run" ,(1000 * randomNumber(1,5)));
1
BusterLuke

アロー関数の構文を使用できます。

setTimeout(() => {
     this.doStuff();
 }, 4000);
1
Mioe Galaxy

文字列を使用してsetTimeoutまたはsetIntervalを使用することはお勧めしません

setTimeout("myFunction()", 5000);

//this is the same as 

setTimeout(function(){ eval("myFunction()"); }, 5000)); //<-- eval == BAD
0
Vitim.us

より複雑な状況に遭遇しました...クラスAには、タイプBのメンバーと、クラスBのメソッドを呼び出すsetTimeoutを呼び出すメソッドがあります。次のように解決されます。

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

B.tick内でこれにA.bをバインドして機能しました。

これがbindのフィドルです: https://jsfiddle.net/jrme9hyh/

そして、失敗するbindがないもの: https://jsfiddle.net/2jde8tq3/

0
philn5d

短い道。匿名機能なし。

    var self = this;
    setTimeout(self.method, 1000);
0
Ngorco

代わりに、このコードを使用できます。これは、すべての最新ブラウザーで機能します-

setTimeout(function(thisObj) {thisObj.run();},1000,this);

参照: http://klevo.sk/javascript/javascripts-settimeout-and-how-to-use-it-with-your-methods/

0
KalEl
class A{

   setTimeout(()=>{

       // here this != undefined because of arrow function

  },500);

}
0
M Ahmed Mushtaq