4

Angularjs の UI アドオンの例をいくつか読んでいると、Javascript に関する私の知識が非常に改善可能であることを示すいくつかのコードに出くわしました。

以下は、Angular プロバイダー内のクラスです。

function Dialog(opts) {

            var self = this, options = this.options = angular.extend({}, defaults, globalOptions, opts);
            this._open = false;

            this.backdropEl = createElement(options.backdropClass);
            if(options.backdropFade){
                // ...
            }

            this.handleLocationChange = function() {
                self.close();
            };

            // more functions
        }

かなり簡単です。ただし、そのクラスの外には、プロトタイプ関数があります。たとえば、上記の呼び出しclose()

Dialog.prototype.open = function(templateUrl, controller){
            var self = this, options = this.options;

            // .. some code
        };

その関数がプロトタイプとして宣言されている理由がわかりませんがhandleLocationChange、クラス自体の内部にあります。

どの方法を選択するかはどのように決定すればよいですか?

完全な要点はここで見つけることができます

4

3 に答える 3

3

次の 2 つのケースを考えてみましょう。

Dialog.prototype.open = function...

Dialog.open = function....

最初のケース - 呼び出しによって作成されたすべてのオブジェクトnew Dialog()には、このopen関数があります

2 番目のケースは、ダイアログ オブジェクトとは関係ありません。静的関数と考えてください。

編集

ここで素晴らしい答えを見つけました:javascript-class-method-vs-class-prototype-method

于 2013-06-26T07:46:52.430 に答える
2

handleLocationChange は、リスナーを登録するがthisコンテキストを登録しないイベントトリガーオブジェクトから呼び出されると思います。そのため、トリガーされると、handleLocationChange を参照するので使用できませんthis。これを克服するために、彼らはクロージャー参照を this (= self 変数) に設定し、self を使用して他のインスタンス関数を呼び出すことを選択しました。基本的に、作成時に既知の値を格納していますが、handleLocationChange の実​​行時には不明です。

問題を示すコードを次に示します。

var eventSystem={
  events:{},
  add:function(eventname,fnCallback){
     if(!this.events[eventname]){
      this.events[eventname]=[];
     }
     this.events[eventname].push(fnCallback);
  },
  trigger:function(eventname){
    if(!this.events[eventname]){
      return;
    }
    var i=0;
    for(i=0;i<this.events[eventname].length;i++){
      this.events[eventname][i]();
    }
  }
};

var person=function(name){
  this.name=name;
};
person.prototype.sayName=function(){
  console.log("this is now:",this.toString());
    // logs this is now: function (){ console.log("this is now:...
    // so this is now the sayName function not the person instance
  console.log(this.name);//undefined: sayName doesn't have a name property
}
var jon=new person("jon");
eventSystem.add("sayname",jon.sayName);//add event and listener function
eventSystem.trigger("sayname");//trigger the event

クロージャー参照を設定して解決する方法は次のとおりです

var eventSystem={
  events:{},
  add:function(eventname,fnCallback){
     if(!this.events[eventname]){
      this.events[eventname]=[];
     }
     this.events[eventname].push(fnCallback);
  },
  trigger:function(eventname){
    if(!this.events[eventname]){
      return;
    }
    var i=0;
    for(i=0;i<this.events[eventname].length;i++){
      this.events[eventname][i]();
    }
  }
};

var person=function(name){
  var self=this;// set closure ref to this
  this.name=name;
  this.sayName=function(){
    console.log(self.name);//use closure ref to get this
       // logs jon
  }
};
var jon=new person("jon");
eventSystem.add("sayname",jon.sayName);//add event and listener function
eventSystem.trigger("sayname");//trigger the event

thisコンテキストを処理するためのイベント システムの修正を次に示します。

var eventSystem={
  events:{},
  add:function(eventname,fnCallback,thisRef){
     if(!this.events[eventname]){
      this.events[eventname]=[];
     }
     this.events[eventname].push({
       "callback":fnCallback,//store the event handler
       "thisRef":thisRef//store the this context
     });
  },
  trigger:function(eventname){
    if(!this.events[eventname]){
      return;
    }
    var i=0;
    for(i=0;i<this.events[eventname].length;i++){
      this.events[eventname][i].callback.call(
        this.events[eventname][i].thisRef);
    }
  }
};

var person=function(name){
  this.name=name;
};
person.prototype.sayName=function(){
  console.log("this is now:",this);//referring to person instance
    // with the name jon
  console.log(this.name);//logs jon
  console.log(this instanceof person);//true
}


var jon=new person("jon");
eventSystem.add("sayname",jon.sayName,jon);//add extra parameter for this ref
eventSystem.trigger("sayname");//trigger the event

上記で使用されているパターンは、イベント システムではありません (より強力なサブスクライバーだと考えてください)。イベントは通常、オブジェクト (ボタン、入力、ダイアログ) でトリガーまたは呼び出されますが、実装のようなイベント システムの場合は簡単に取得できます。thisインスタンス (myButton や myDialog など) で、またはインスタンスからイベントをトリガーするため、正しいコンテキスト。

イベント システムのような実装については、次のコードを参照してください。

var eventSystem={
  add:function(eventname,fnCallback){
     if(!this.events[eventname]){
      this.events[eventname]=[];
     }
     this.events[eventname].push(fnCallback);
  },
  //change in trigger as it's passing the event object now
  trigger:function(event){
    if(!this.events[event.type]){
      return;
    }
    var i=0;
    for(i=0;i<this.events[event.type].length;i++){
      this.events[event.type][i](event);
    }
  },
  initES:function(){//set the instance variables needed
    this.events=this.events||{};
  }
};
function addProtos(o,protos){
  for(item in protos){
    o.prototype[item]=protos[item];
  }
}
var person=function(name){
  this.name=name;
  this.initES();//needed to initialeze eventsystem
};
// make person capable of storing event handlers
// and triggering them
addProtos(person,eventSystem);
person.prototype.askQuestion=function(){
  //asking a question will trigger an "answer" event
  this.trigger({type:"answer",target:this});
}
// handler for when jon will fire an answer event
function answerHandler(event){
  console.log("answer from:",event.target);
  console.log("name of the person:",event.target.name);
}

var jon=new person("jon");
jon.add("answer",answerHandler);//add event listener
jon.askQuestion();//triggers the answer event from within jon
jon.trigger({type:"answer",target:jon});//trigger the event externally

Angular がクロージャーを使用してプロトタイプを「壊す」ことを選択した理由がわかりません。例は他の選択肢があることを示しています。たぶん、誰かが Angular に詳しい人を説明できるでしょう。

于 2013-06-26T07:59:26.590 に答える
2

関数 open は new Dialog().. を使用して作成されたすべてのオブジェクトで共有され、handleLocationChange はオブジェクトごとに異なります。

于 2013-06-26T07:44:13.723 に答える