我认为handleLocationChange是从注册监听器但不注册this
上下文的事件触发对象调用的,所以当它被触发时你不能使用this
它,因为它指的是handleLocationChange。为了克服这个问题,他们选择设置对 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
上面使用的模式不是事件系统(认为它是 pulisher 订阅者),因为事件通常会在对象(按钮、输入、对话框)上触发或调用,但在更多事件系统(如实现)的情况下,很容易获得正确的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。