今天我使用Javascript的prototype
和this
引用遇到了一个非常奇怪的问题。
基本上,我有两个对象。一个对象使用div
元素,并且可以在onclick
上注册div
事件。另一个对象使用此功能并使用第一个对象注册onclick
事件。
以下是代码:
我的第一个对象,负责div
:
DivObject = function() {};
DivObject.prototype.setClickListener = function(clickListener){
document.getElementById("myDiv").onclick = function(e){
clickListener(e);
};
};
我的第二个对象使用此功能:
MainObject = function(){
this.myString = "Teststring";
this.divObj = new DivObject();
this.divObj.setClickListener(this.handleClick);
};
MainObject.prototype.handleClick = function(e){
// do something with e
};
问题是,在MainObject.prototype.handleClick
内,this
引用引用window
对象,而不引用MainObject
。因此,此函数中的console.log(this)
会记录[Object window]
。
You can see this behaviour on jsfiddle.
作为一种解决方法,我使用setClickListener
函数,如下所示:
var thisRef = this;
this.divObj.setClickListener(function(e){
thisRef.handleClick(e);
});
现在,this
函数中的handleClick
引用引用了我的MainObject
(我希望它是这样)。
See this workaround on jsfiddle.
我的问题是:
为什么this
引用一次引用window
对象,一次引用我对象的this
引用?它在某处被覆盖了吗?我一直认为在我的对象中使用this
我可以肯定它实际上是我对象的this
引用?我现在使用的解决方法是如何解决这个问题的方法,还是有其他更好的方法来处理这种情况?
答案 0 :(得分:1)
您可以使用 .bind() 解决此问题:
this.divObj.setClickListener(this.handleClick.bind(this));
的 See the demo. 强> 的
答案 1 :(得分:1)
您的问题:
为什么这个引用一次引用窗口对象,一次引用我对象的this引用?
除了使用 bind 之外,函数this
的值由函数的调用方式设置。当你这样做时:
this.divObj.setClickListener(this.handleClick);
您正在分配函数引用,因此无需任何限定即可调用该函数。在进入函数时,由于调用未设置其this
,因此它将默认为全局(窗口)对象,或者在严格模式下保持未定义。
它在某处被覆盖了吗?
不,在进入执行上下文时设置this
的值。您无法覆盖它或直接分配给它,您只能在调用中设置它(例如,作为对象的方法,使用 new , apply ,调用)或使用 bind 。
我一直认为在我的对象中使用它我可以肯定它实际上是我对象的这个引用?
在您完成作业时,this
就是您所期望的。但是你要分配一个对funciotn的引用,而不是调用该函数,所以它的this
不会在那个时刻设置,而是在它被调用的时候设置。
我现在使用的解决方法是如何解决这个问题的方法,还是有其他更好的方法来处理这种情况?
你的工作很好(和一个常见的修复),它创建一个闭包,所以可能会有轻微的记忆后果,但没有什么严重的。对于非常旧版本的IE,由于涉及DOM对象的循环引用会导致内存泄漏,但这是固定的。
从清晰度和维护角度来看, bind 解决方案可能更好。请记住为没有内置支持 bind 的浏览器添加“猴子补丁”。
请在SO上发布代码,不保证在其他地方发布的代码将继续可访问。围绕代码的工作:
MainObject = function(){
this.myString = "Teststring";
this.divObj = new DivObject();
var thisRef = this;
this.divObj.setClickListener(function(e){
thisRef.handleClick(e);
});
};