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();
}
}
}
あなたはこれを行うことができます:
var that = this;
setTimeout(function () {
that.doStuff();
}, 4000);
また、 bind
より簡潔なコード(@Raynosによって最初に指摘されたように)を使用することもできます。
setTimeout(this.doStuff.bind(this), 4000);
bind
は、まさにこのコーディングパターンの標準ライブラリ関数です(つまり、this
をレキシカルにキャプチャします)。
関数をスコープにバインドすることもできます。
setTimeout(this.run.bind(this) ,(1000 * randomNumber(1,5)));
警告Function.prototype.bind
はES5です
あなたが発見したように、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)));
}
}
this.wait = function(){
var self = this;
window.setTimeout(function() { self.run() } ,(1000 * randomNumber(1,5)));
}
したがって、.runを呼び出すオブジェクトへの参照をローカル変数( 'self')に格納します。
this
は、それが呼び出されるコンテキストに依存します。文字列をsetTimeout
に渡すと、完全に異なるコンテキストでeval
edされます。
this
の現在の値を保持し(別の変数にコピーすることにより)、スコープを維持する必要があります(暗黙のeval
を使用しないことにより)。
this.wait = function(){
var self = this;
setTimeout(function () { self.run() },
(1000 * randomNumber(1,5))
);
}
メインmyObject
の上部で、this
の現在の値への新しい参照を作成します。
var self = this;
次に、setTimeout
がコールバックのデフォルトコンテキストとして使用するグローバルオブジェクトの代わりに、その新しい参照を使用するタイマーコールバックのクロージャーを作成します。
setTimeout(function() {
self.run();
}, 4000);
var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);
内部func
、this
は常にグローバルオブジェクトを参照します。現在のオブジェクトをfuncに渡すことができます。
var timeoutID = window.setTimeout(func, delay, this);
function func(that) {...}
残念ながらIEでは機能しません
最初の構文で関数に追加のパラメーターを渡すことは、Internet Explorerでは機能しないことに注意してください。
やってみました;
window.setTimeout("myObject.run" ,(1000 * randomNumber(1,5)));
アロー関数の構文を使用できます。
setTimeout(() => {
this.doStuff();
}, 4000);
文字列を使用してsetTimeoutまたはsetIntervalを使用することはお勧めしません
setTimeout("myFunction()", 5000);
//this is the same as
setTimeout(function(){ eval("myFunction()"); }, 5000)); //<-- eval == BAD
より複雑な状況に遭遇しました...クラス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/
短い道。匿名機能なし。
var self = this;
setTimeout(self.method, 1000);
代わりに、このコードを使用できます。これは、すべての最新ブラウザーで機能します-
setTimeout(function(thisObj) {thisObj.run();},1000,this);
参照: http://klevo.sk/javascript/javascripts-settimeout-and-how-to-use-it-with-your-methods/
class A{
setTimeout(()=>{
// here this != undefined because of arrow function
},500);
}