我定义了一个“类”,并且只创建了一个实例。该实例拥有一个最终被传递的成员函数(它是一个鼠标处理程序,但这并不重要)。由于我只会创建一个“类”的实例,所以我决定使用对象文字将其重写为单例。
所以我有
var mySingleton = {
theObjects : [];
}
mySingleton.mouseHandler = (function() {
var that = this;
return function (e) {
for (var indx = 0; indx < that.theObjects.length; indx++) {
// do something to that.theObjects[indx];
}
}
}());
mySingleton.addObject = function(newObj) {
this.theObjects.push(newObj);
}
然而,当我尝试使用这段代码时(在添加几个对象之后),我不断得到一个.theObjects是未定义的错误。它指的是for循环中的行。
答案 0 :(得分:7)
2015年更新 - 使用Function.bind()
指定功能中this
的值。然后,您可以使用that
。
this
mySingleton.mouseHandler = function (e) {
for (var indx = 0; indx < this.theObjects.length; indx++) {
// do something to this.theObjects[indx];
}
}.bind(mySingleton);
如果您希望mouseHandler
具有'moused'元素的上下文,则此方法无效。为此,请使用下面的原始答案。
如果您之前需要支持IE8或(天堂禁止),则需要使用polyfill。
由于您正在调用立即创建mouseHandler
的函数,因此它在window
而非mySingleton
的上下文中运行。因此that
是指window
。不要立即调用它,只需将其更改为方法,以便它在mySingleton
的上下文中运行:
mySingleton.getMouseHandler = function() {
var that = this;
return function() { ... };
};
myElement.onclick = mySingleton.getMouseHandler();
当然,由于您已经在使用单例,因此您可以直接引用它。在您的点击处理程序中,检查that.theObjects
,而不是检查mySingleton.theObjects
。或者,在mouseHandler
中将var that = this
更改为var that = mySingleton
。
编辑或者,在调用它时将上下文传递给您的匿名函数:
mySingleton.mouseHandler = (function() {
var that = this;
return function (e) {
for (var indx = 0; indx < that.theObjects.length; indx++) {
// do something to that.theObjects[indx];
}
}
}).call(mySingleton);
答案 1 :(得分:1)
有一些流行的方法可以做到这一点。首先,超简单的解决方案是直接引用mySingleton并绕过与this
相关的混淆。而不是that.theObjects
只做mySingleton.theObjects
而继续你的生活,事情会很好。
但是,这种绑定有一个共同的模式。这是how underscore.js does it
查看annoted source to underscore,您会在哪里找到
_.bind = function(func, obj) {
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
var args = slice.call(arguments, 2);
return function() {
return func.apply(obj, args.concat(slice.call(arguments)));
};
};
答案 2 :(得分:0)
到目前为止,其他答案也是正确的。在这里提供我的观点以防万一。
理解代码无法按预期运行的原因的关键是要了解this
在JavaScript中的工作原理。问题是this
取决于函数的调用方式。
首先,如果您以方法样式调用该函数,this
就是您所期望的:
mySingleton.mouseHandler(); // this === mySingleton
如果你将函数附加到esle上,那也可以。
var anotherSingleton = {};
anotherSingleton.foo = mySingleton.mouseHandler;
anotherSingleton.foo(); // this === anotherSingleton
如果分离该函数,this
将成为全局范围对象(window
)
var foo = mySingleton.mouseHandler;
foo(); // this === window
最后,您可以使用this
或call
强制apply
成为其他内容:
var randomThingy = {};
mySingleton.mouseHandler.call(randomThingy); // this === randomThingy
需要注意的是,this
是在运行时根据函数调用的上下文确定的。通常,允许您通过隐式地代表您应用绑定模式,使“类”从您那里抽象出这些细节的框架。这就是它过去工作的原因,而不再适用。
正如其他人所提到的,您可以更改处理程序以通过其范围名称(mySingleton
)引用变量,或者按照讨论的方式绑定它。
这是几年前我就这个主题撰写的一篇文章,详细介绍了http://trephine.org/t/index.php?title=Understanding_JavaScript%27s_this_keyword
希望这有帮助!