JavaScriptのブラウザパターンと呼び出しコンテキスト

「Observer(Observer、Observer)」というパターンについては、Habréを含めて十分に述べられていますが、簡単に繰り返します。 このパターンの本質は、システムの特定の被験者の状態と、これらの状態の変化に対する観察者の対応を監視することにあります。 さらに、複数のオブザーバーが1つのサブジェクトを追跡できます。さらに、彼自身はそのサブジェクトについては知りませんが(弱い結合)、状態の変化について定期的に全員に通知します。



ブラウザをサイトやWebアプリケーションで使用すると便利なため、Web環境で最も一般的な言語であるJavascriptを使用して実装することは理にかなっています。



Observable = function() {  this.observers = []; } Observable.prototype.deliver = function(data) {  for (var i in this.observers) {   this.observers[i](data);  } } Function.prototype.subscribe = function(observable) {  observable.observers.push(this);  return this; }
      
      





すべてがシンプルです。 Observableクラスが主題です。 オブザーバーの配列-サブスクライバー、オブザーバー。 deliverメソッドは、オブザーバーに状態の変化を通知します。 購読者はオブザーバーに署名します。 実際には、次のようになります。



 myClass = function() { this.value = 0; //  this.onChange = new Observable(); //  } myClass.prototype.change = function(new_value) { this.value = new_value; this.onChange.deliver(this.value); //  —   } var c = new myClass(); var write_log = function(value) { console.log(value); } write_log.subscribe(c.onChange);
      
      





すばらしい実例:c.valueが変更されるたびに、onChange observableはすべてのオブザーバーに変更を通知し、オブザーバーが独自の方法で管理する新しい状態を通知します。 したがって、たとえば、write_log()はコンソールに新しい状態を出力します。 しかし、この例は、郵送後に実行される関数でこれを操作する必要が生じるまで顕著です。



したがって、たとえば、次の構成は正常に機能しません。



 myClass = function() { this.value = 0; this.onChange = new Observable(); } myClass.prototype.change = function(new_value) { this.value = new_value; this.onChange.deliver(this.value); } Logger = function(logtype) { this.type = (!!logtype) ? logtype : "alert"; } Logger.prototype.write = function(value) { if (this.type == "console") { console.log(value); return; } alert(value); } var c = new myClass(); var logger = new Logger("console"); logger.write.subscribe(c.onChange);
      
      





logger.writeの実行中にこれにアクセスすると問題が発生します。 これはコンテキストであり、この場合、コンテキストはLoggerクラスのインスタンスではなく、deliverの実行時に呼び出される匿名関数()関数であることを思い出させてください。



すばらしい呼び出し機能は、特定のメソッドを実行するだけでなく、実行コンテキストを指定できる問題の解決に役立ちます。 そのため、観察可能なメソッドを少し書き直して配信し、それに応じてサブスクリプションメカニズムを変更しました。



 Observable = function() { //  this.observers = []; } Observable.prototype.deliver =function(data) { for (var i in this.observers) {  this.observers[i].func.call(this.observers[i].context, data); //      } } Function.prototype.subscribe = function(observable, context) { var ctx = context || this; //    ,    this «-»,     var observer = { //   ,        context: ctx,  func: this } observable.observers.push(observer); return this; }
      
      





したがって、極端な例が機能するためには、サブスクリプションでの呼び出しのコンテキスト(Loggerのインスタンス)を示すだけで済みます。



 var logger = new Logger("console"); logger.write.subscribe(c.onChange, logger);
      
      





うまくいく! そして、この小さなトリックが誰かに役立つことを願っています。




All Articles