2011-01-18 1 views
2

コールバックからアクションを受け取るオブジェクトを使用する次のコード例があります。これは良いデザインパターンではないようです。またはそれは?Javascriptのコールバックを適切に使用していますか(オブジェクト指向スタイル)ですか?

setTimeOut()は、1秒後にファンクションを起動すると、objInstanceグローバル変数(DOMスコープ)を使用してClassExampleオブジェクトインスタンスにアクセスします。誰かがオブジェクト指向設計内でコールバックを利用するより良い方法をお勧めしますか?

私は、オブジェクトインスタンス内のデータを更新するためにコールバックを使用できます(変数を増やすなど)。

function ClassExample{ 
    this.initiate = function() { 
     setTimeOut(objInstance.afterTimeOut,1000); //using the objects global handle 
    } 

    this.afterTimeOut = function() { 
     alert("Received!"); 
    } 

} 

var objInstance = new ClassExample(); //instance 
objInstance.initiate(); 
+2

待ち、ワットと

OOP?それはそれを過大に扱うような畏敬の念を抱いています(Javaなどでよく見られるような)。どうして 'setTimeOut(function(){...}、n)'(おそらく関数を前もって別々に作成し、わかりやすい名前をつけているのでしょうか)。あなたが使用していた機能的プログラミングの垣間見ることを恐れてはいけません。 – delnan

+0

私は「over-OOP」という言葉が好きです.Javascriptの* lots *を記述しているからです。私はJavaとは根本的に異なる方法を理解していませんでした.- – Pointy

答えて

4

いいえ、そうではありません。あなたはこれを実行することをお勧めします:

this.initiate = function() { 
    setTimeOut(objInstance.afterTimeOut,1000); //using the objects global handle 
} 

、 "afterTimeoutは" 適切なオブジェクトコンテキストを必要とする場合、あなたはこれを行うことができます:

this.initiate = function() { 
    var instance = this; 
    setTimeout(function() { instance.afterTimeOut(); }, 1000); 
} 

OKだけでなく、あなたが質問を変更しました私があなただったら、元の第2の例のようにこれをやってみましょう:

this.initiate = function() { 
    var instance = this; 
    setTimeout(function() { instance.afterTimeOut(); }, 1000); 
} 

その後、まったく醜いグローバル変数は必要ありません。

編集 — Stackoverflowのユーザー@Christophは、これは特にあまり美しいとは言いません。新しいブラウザでネイティブに(Functionプロトタイプのメソッドとして)、またはいくつかのライブラリ(PrototypeやFunctionalなど)によって提供されるように、「バインド」機能を使用することが役立ちます。 「バインド」に呼んで

this.initiate = function() { 
    setTimeout(this.afterTimeOut.bind(this), 1000); 
} 

が効果的に、私はコード化された小さなラッパーとしてのものと同じ種類である関数を返す:どのような「バインドする」私は上記の持っているように、あなたが少しラッパー関数を作成している行うことができますこの例では明示的に指定します。

+0

その編集については申し訳ありませんが、見つけていただきありがとうございます。 – Ryan

+0

+1これは、私の答えを無視して、それを行う方法ですが、私のオープニングステートメントを考慮する:) –

+1

"instance.afterTimeOut()"と言っているのですか? – Ryan

0

あなたが目指していることを行う最適な方法ではありません。しかし、なぜ私はあなたが開始の一環としてコールスタックを壊す必要があるのだろうか、それは非常に学術的だと思う必要があります。別に私はそれをしなければならなかった場合、私はおそらくそうのような閉鎖を使用したいということから

は:

function ClassExample{ 
    this.initiate = function() { 
     setTimeOut((function(self) { return function() { self.afterTimeout();}})(this),1000); //using the objects global handle 
    } 

    this.afterTimeOut = function() { 
     alert("Received!"); 
    } 

} 

var objInstance = new ClassExample(); //instance 
objInstance.initiate() 
2
function ClassExample{ 
    this.afterTimeOut = function() { 
     alert("Received!"); 
    }; // Don't forget these 

    setTimeOut(afterTimeOut, 1000); // Don't use() if you're passing the function as an argument 
} 

var objInstance = new ClassExample(); //instance 

そのように、あなたはinitiate()方法を必要としません。あなたが本当にinitiate()方法をしたい場合は


、私はこのようにそれを行うだろう:

function ClassExample{ 
    var self = this; 

    self.afterTimeOut = function() { 
     alert("Received!"); 
    }; 

    self.initiate = function() { 
     setTimeOut(self.afterTimeOut, 1000); 
    }; 

} 

var objInstance = new ClassExample(); //instance 
objInstance.initiate(); 
0
this.initiate = function() { 
    var instance = this; 
    setTimeOut(function() { 
     instance.afterTimeOut(); 
    }, 1000); 
}; 

ローカル変数にthisを保存することで、あなたは、すべてのグローバルハンドルを使用して回避することができます。また、これによってafterTimeout()が失われるのを防ぐことができます。this

1

これは私がタイマーの再利用を許可し、クロージャの数最小限に抑えるためにそれを行うだろうかです:

function Timer(timeout, callback) { 
    this.timeout = timeout; 
    this.callback = callback; 
} 

Timer.prototype.run = function(thisArg /*, args... */) { 
    var argArray = Array.prototype.slice.call(arguments, 1); 
    var timer = this; 

    setTimeout(function() { 
     timer.callback.apply(thisArg, argArray); 
    }, timer.timeout); 
}; 

var timer = new Timer(1000, alert); 
timer.run(null, 'timer fired!'); 

そして、ちょうど楽しみのために、機能的に同等であるgolfedバージョンが、オブジェクトを置き換えます閉鎖で:Znarkusの答えに

function delay(func, timeout) { 
    return function() { 
     var self = this, args = arguments; 
     setTimeout(function() { func.apply(self, args); }, timeout); 
    }; 
} 

delay(alert, 1000).call(null, 'timer fired!'); 
+0

私は本当に単純な自己=この例よりも利益を見ているかわかりません。あなたは説明できますか?ありがとう! – Ryan

+1

@ Ryan:これは同じ方法で動作します( 'self'だけが' timer'と呼ばれます)。しかし、あなたは「良いデザイン」を求めていました。再利用性(汎用の「Timer」クラス)、読みやすさ(正常な命名)、効率性(コンストラクタからメソッドを引き出すことは、インスタンスごとに1つではなく1つの関数オブジェクトを作成する必要があることを意味します) 'Timer'オブジェクトの' run() 'のシグネチャは' Function'オブジェクトの 'call()'と同じです) – Christoph

0

ビル...

私は本当にWHIには分かりません私の場合、最初のアプローチはうまくいきません。私が得た:「にReferenceError:afterTimeOutはに定義されていない」

もう一つは、それにもかかわらず、...私は本当にクールな(「O」の小文字を使用)のsetTimeoutのためのsetTimeoutを変更した後の括弧に含まれています...コードの最初の行を 'function ClassExample(){';}に変換するクラス名定義。私の問題を解決しました。サンプルコードの

マイスニペット:プライベートの行動、インターンのコールバック呼び出しとなど

function MyTry (name){ 
    // keep this object pointer... that's the trick! 
    var self = this; 

    // create private variable 
    var d = new Date()toJSON().slice(0, 10); 

    // create a private function 
    function getName(){return name} 

    // create public access method 
    self.hello = function(){alert('Hello '+getName()+'!\nToday is: '+d)} 

    // note instance method hello passed as a callback function! 
    self.initiate = function(){setTimeout(self.hello, 3000)} 
} 
関連する問題