[英]scope when doing OO javascript callbacks
Folks - I'm trying to learn how to write OO Javascript, I come from as3 OO background... issue I'm having is with passing a class' method as a callback to another class... 伙计们 - 我正在努力学习如何编写OO Javascript,我来自as3 OO背景...我遇到的问题是将一个类'方法作为回调传递给另一个类...
in the example below, i create an instance of AppController class, and in it, i create an instance of ConnectionMonitor class. 在下面的示例中,我创建了一个AppController类的实例,在其中,我创建了一个ConnectionMonitor类的实例。 I pass one of AppController's methods to be called back by ConnectionMonitor.
我传递一个AppController的方法,由ConnectionMonitor调用。 The calling back works fine, but seems that what's inside the callback function looses the scope of the class its in (AppController )...
回调工作正常,但似乎回调函数内部的内容失去了它的范围(AppController)......
any thoughts? 有什么想法吗?
//in the HTML
<script>
$(document).ready( function(){
new AppContoller().init();
});
</script>
//in the js file
//AppController Class
var AppContoller = function(){
this.body = $("body");
this.init = function(){
this.connection = new ConnectionMonitor();
this.connection.detectInitialConnection( this.initialConnectionDetected );
}
//callback function I pass
this.initialConnectionDetected = function(bool){
if(bool){
trace("app connected? "+bool); // logs - "app connected? true"
this.showOnlineSwf(); //thows error - "Object [object DOMWindow] has no method 'showOnline' "
}
else{
}
}
this.showOnlineSwf = function(){
trace("i'm online");
}
}
//ConnectionMonitor Class
var ConnectionMonitor = function()
{
this.detectInitialConnection = function(callbackFunction){
setTimeout(callbackFunction, 1000, [true]);
}
}
function trace(arg){
console.log(arg.toString());
}
Modify init
to bind the callback to the original context: 修改
init
以将回调绑定到原始上下文:
this.init = function() {
this.connection.detectInitialConnection(
this.initialConnectionDetected.bind(this));
}
Unfortunately, bind
is not supported in all browsers , but you can capture the current value of this
in a closure to achieve a similar effect: 不幸的是,
bind
是不是在所有的浏览器都支持 ,但是你可以捕捉的当前值this
在一个封闭来达到类似的效果:
this.init = function() {
var that = this;
this.connection.detectInitialConnection(function(detected) {
that.initialConnectionDetected(detected);
});
}
Yet another approach is to make detectInitialConnection
capable of handling an optional context parameter: 另一种方法是使
detectInitialConnection
能够处理可选的上下文参数:
this.detectInitialConnection = function(callbackFunction, _this){
setTimeout(function() {
callbackFunction.apply(_this || this, arguments);
}, 1000, [true]);
}
You'd then call it like this: 然后你会这样称呼它:
this.init = function() {
this.connection.detectInitialConnection(
this.initialConnectionDetected, this);
}
The point in each of these examples is to retain a reference to the value of this
from the context in which detectInitialConnection
was called. 这些示例中的每一个中的要点是从调用
detectInitialConnection
的上下文中保留对this
的值的引用。
setTimeout will run the passed function bound to window
. setTimeout将运行绑定到
window
的传递函数。 You can override this with ES5's bind
: 您可以使用ES5的
bind
覆盖它:
this.connection.detectInitialConnection( this.initialConnectionDetected.bind(this) );
This doesn't work in older browsers, but the provided MDN link has a workaround. 这在旧版浏览器中不起作用,但提供的MDN链接有一个解决方法。
this is tricky in javascript especially as it relates to constructors and passing functions around. 这在javascript中很棘手,特别是因为它与构造函数和传递函数有关。 If you do this it will work:
如果你这样做它会工作:
//AppController Class
var AppContoller = function(){
this.body = $("body");
var self = this;
this.init = function(){
this.connection = new ConnectionMonitor();
this.connection.detectInitialConnection( this.initialConnectionDetected );
}
//callback function I pass
this.initialConnectionDetected = function(bool){
if(bool){
trace("app connected? "+bool); // logs - "app connected? true"
self.showOnlineSwf();
}
else{
}
}
this.showOnlineSwf = function(){
trace("i'm online");
}
}
this.initialConnectionDetected
will pass the function, but without the information that it should be executed on the instance. this.initialConnectionDetected
将传递该函数,但没有它应该在实例上执行的信息。
Calling this.foo()
will pass this information, but only when called directly, not when passed around and called later (which is what you're doing). 调用
this.foo()
将传递此信息,但仅在直接调用时,而不是在传递并稍后调用时(这是您正在执行的操作)。
You have to bind this information (ie the this
value, which is the instance) using eg .bind
: 您必须使用例如
.bind
绑定此信息(即this
值,即实例):
this.connection.detectInitialConnection(this.initialConnectionDetected.bind(this));
Note that .bind
is not available in older browsers, but there are shims available which mimic the behaviour of it. 请注意,
.bind
在旧版浏览器中不可用,但有可用的填充程序模仿它的行为。
The other answers are correct, but nobody seems to mention that Function.prototype.bind
is not supported in all browsers . 其他答案是正确的,但似乎没有人提到所有浏览器都不支持
Function.prototype.bind
。 To make it work, you'll want to include Kris Kowal's es5-shim library . 为了使它成功,你需要包括Kris Kowal的es5-shim库 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.