web-dev-qa-db-ja.com

Javascript setIntervalおよび「this」ソリューション

thisハンドラーからsetIntervalにアクセスする必要があります

prefs: null,
startup : function()
    {
        // init prefs
        ...
        this.retrieve_rate();
        this.intervalID = setInterval(this.retrieve_rate, this.INTERVAL);
    },

retrieve_rate : function()
    {
        var ajax = null;
        ajax = new XMLHttpRequest();
        ajax.open('GET', 'http://xyz.com', true);
        ajax.onload = function()
        {
            // access prefs here
        }
    }

ajax.onloadでthis.prefsにアクセスするにはどうすればよいですか?

60
Pablo

SetInterval行は次のようになります。

 this.intervalID = setInterval(
     (function(self) {         //Self-executing func which takes 'this' as self
         return function() {   //Return a function in the context of 'self'
             self.retrieve_rate(); //Thing you wanted to run as non-window 'this'
         }
     })(this),
     this.INTERVAL     //normal interval, 'this' scope not impacted here.
 ); 

編集:同じ原理が "onload"にも適用されます。この場合、「外部」コードはほとんど何もしないのが一般的で、リクエストを設定して送信するだけです。この場合、上記のコードのように追加のオーバーヘッドを追加する必要はありません。 retrieve_rateは次のようになります。

retrieve_rate : function()
{
    var self = this;
    var ajax = new XMLHttpRequest();
    ajax.open('GET', 'http://xyz.com', true);
    ajax.onreadystatechanged= function()
    {
        if (ajax.readyState == 4 && ajax.status == 200)
        {
            // prefs available as self.prefs
        }
    }
    ajax.send(null);
}
85
AnthonyWJones
this.intervalID = setInterval(this.retrieve_rate.bind(this), this.INTERVAL);
77
Nechehin

setIntervalのデフォルトの動作は、グローバルコンテキストにバインドすることです。現在のコンテキストのコピーを保存して、メンバー関数を呼び出すことができます。 retrieve_rate内では、this変数は元のコンテキストに正しくバインドされます。コードは次のようになります。

var self = this;
this.intervalID = setInterval(
    function() { self.retrieve_rate(); },
    this.INTERVAL);

おまけのヒント:(メンバー関数を持つオブジェクト参照ではなく)単純な関数参照の場合、JavaScriptのcallまたはapplyメソッドを使用してコンテキストを変更できます。

18
Joel Fillmore

ブラウザーのサポートが改善されたことで、 EcmaScript 6の機能強化、矢印_=>_メソッド を使用してthisを適切に保持できるようになりました。

_startup : function()
    {
        // init prefs
        ...
        this.retrieve_rate();
        this.intervalID = setInterval( () => this.retrieve_rate(), this.INTERVAL);
    },
_

=>メソッドを使用すると、retrieve_rate()が間隔によって呼び出されたときにthisが保持されます。ファンキーな自己やパラメーターでthisを渡す必要はありません

11
Martlark

window.setInterval(function(){console.log(this)}.bind(this), 100)

これはjavascriptで合法であり、多くのコードを保存します:)

7

ほとんどの場合、実際の連続したメソッド呼び出しでthisコンテキストを切り替えたいので、これが最もクリーンなソリューションになります。

また、概念を把握するのも簡単です。

    // store scope reference for our delegating method
    var that = this;
    setInterval(function() {
        // this would be changed here because of method scope, 
        // but we still have a reference to that
        OURMETHODNAME.call(that);
    }, 200);
2
Dbl

最新のブラウザでは、setIntervalメソッドを使用すると、タイマーの期限が切れるとfuncで指定された関数に渡される追加のパラメーターを使用できます。

var intervalID = scope.setInterval(func、delay [、param1、param2、...]);

したがって、可能な解決策は次のとおりです。

this.intervalID = setInterval(function (self) {
        self.retrieve_rate();
    }, this.INTERVAL, this);

デモ:

var timerId;
document.querySelector('#clickMe').addEventListener('click', function(e) {
    timerId = setInterval(function (self) {
        self.textContent = self.textContent.slice(0, -1);
        if (self.textContent.length == 0) {
            clearInterval(timerId);
            self.textContent = 'end..';
        }
    }, 250, this);
})
<button id="clickMe">ClickMe</button>
0
gaetanoM
prefs: null,
startup : function()
    {
        // init prefs
        ...
        this.retrieve_rate();
        var context = this;
        this.intervalID = setInterval(function()
                                      {
                                          context.retrieve_rate();
                                      }, this.INTERVAL);
    },

retrieve_rate : function()
    {
        var ajax = null;
        ajax = new XMLHttpRequest();
        ajax.open('GET', 'http://xyz.com', true);
        var context = this;
        ajax.onload = function()
        {
            // access prefs using context.
            // e.g. context.prefs
        }
    }
0