Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I think handleLocationChange is called from event triggering object that registers listeners but doesn't register the <code>this</code> context so when it's triggered you can't use <code>this</code> as it refers to handleLocationChange. To overcome this they have chosen to set a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures" rel="nofollow">closure</a> reference to this (=the self variable) and call other instance functions using self. Basically it's storing a value known at creation but not known when handleLocationChange is executing.</p> <p>Here is some code showing the problem:</p> <pre><code>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&lt;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 </code></pre> <p>Here is how it's solved setting a closure reference</p> <pre><code>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&lt;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 </code></pre> <p>Here is a fix to the event system to take care of the <code>this</code> context:</p> <pre><code>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&lt;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 </code></pre> <p>The pattern used above is not an event system (think it's pulisher subscriber) as an event usually get triggered on or invoked from an object (button, input, dialog) but in case of a more event system like implementation it would be easy to get the correct <code>this</code> context since you trigger the event on or from an instance (like myButton or myDialog).</p> <p>See following code for event system like implementation:</p> <pre><code>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&lt;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 </code></pre> <p>Not sure why Angular choose to "break" prototype by using closures as the examples show there are other alternatives. Maybe someone can explain that who is more familiar with Angular.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload