背景:我正在构建一个使用JQuery和Facebook Javascript API的webapp。由于一些用户不喜欢Facebook,我还构建了一个thunking层,为不想使用Facebook的用户模拟必要的身份API。为了保持清洁并避免代码重复,我已将我的Javascript代码组织到几个类中。
Facebook和JQuery API都广泛使用回调。由于我的所有函数都绑定到对象中,因此我发现我经常使用以下模式:
var obj_ref = this;
some_jquery_function_that_takes_a_callback(/* various args */,
function() { obj_ref.my_callback_method(); });
为了便于阅读,obj
中的obj_ref
实际上是该类的名称。
是否有一些更简单或更清晰的漂亮的Javascript魔法,或者它是否能够得到它的好处?
更新:到目前为止答案中有一些好的评论。我应该补充一点,我的回调方法通常需要引用绑定到类的变量或函数。如果我不需要,那么匿名函数包装器是不必要的。
Update2:我选择了最佳答案,但您应该仔细阅读所有答案。每个都为可能的解决方案提供了一些有用的见解。
答案 0 :(得分:2)
如果您需要this
作为obj_ref
并且您可以假设更新日期JavaScript(遗憾的是您可能无法),您可以使用bind
取消包装器:
创建一个新函数,在调用时,它本身在提供的this值的上下文中调用此函数,并在调用新函数时提供任何前面提供的给定参数序列。
然后你可以将你的方法绑定到你的对象上,并且:
some_jquery_function_that_takes_a_callback(/* various args */,
function() { obj_ref.my_callback_method(); });
与:
相同// In some initialization pass...
obj_ref.my_callback_method = obj_ref.my_callback_method.bind(obj_ref);
// And later...
some_jquery_function_that_takes_a_callback(/* various args */,
obj_ref.my_callback_method);
当调用this
时obj_ref
为my_callback_method
。
或者,您可以拉入Underscore.js并使用其bind
或bindAll
。如果你不想要整件事,你总是可以从Underscore.js中抓取bind
或bindAll
。
或者,既然你已经在玩jQuery,你可以使用$.proxy
代替标准bind
:
接受一个函数并返回一个始终具有特定上下文的新函数。
所以你可以这样做:
// In some initialization pass...
obj_ref.my_callback_method = $.proxy(obj_ref.my_callback_method.bind, obj_ref);
// And later...
some_jquery_function_that_takes_a_callback(/* various args */,
obj_ref.my_callback_method);
感谢dsfq提醒我jQuery的bind
版本。
答案 1 :(得分:1)
最好使用绑定到您的对象来保留调用上下文:
var objRef = this;
// #1. In this case you will have wrong context inside myCallbackMethod
// often it's not what you want. e.g. you won't be able to call another objRef methods
someJqueryFunction(a, b, objRef.myCallbackMethod);
// #2. Proper way - using proxy (bind) function
someJqueryFunction(a, b, $.proxy(objRef.myCallbackMethod, objRef));
答案 2 :(得分:1)
我对回调有同样的问题。这就是我处理它的方式。
假设我有一个对象:
var Dog = {
name : "Wolfy",
bark : function(){
console.debug(this.name," barks!");
}
}
var AnotherDog = {
name : "Fang"
}
Dog.bark.call(AnotherDog); //--> Fang barks!
Dog.bark(); //--> Wolfy barks!
当您编写“类”时,可以使用此模式来处理回调的调用。
如果你不确定代理或绑定是做什么的,他们会做类似的事情:
var Dog = {
name : "Wolfy",
bark : function(){
console.debug(this.name," barks!");
}
}
Dog.bark = funciton(){
var scope = Dog;
return Dog.bark.apply(scope,arguments);
}
通过将bark函数包装在一个返回原始函数结果的新函数中来重写函数,但强制使用特定的作用域。
答案 3 :(得分:0)
当我必须传入额外的参数时,我通常只在函数中包装回调:
var x = 42;
jQuery_something({}, function(y, z) { obj_ref.callback(x, y, z) });
这是因为你不能自己控制传递给回调的参数。但这只是在您需要引用范围中的某些var时。在某些情况下,这意味着您必须创建一个闭包来捕获var,例如在一个循环中。
但如果情况并非如此,那么我只是直接传递对该函数的引用:
jQuery_something({}, obj_ref.callback);
即使this
也可以正常工作,因为回调引用在此特定示例的范围内(因此无需先将其复制到obj_ref
:
jQuery_something({}, this.callback);
显然,最后一个示例是简单而干净的:&#34; jQuery方法的回调参数是这个对象的方法,名为&#39; callback&#39; < / EM>&#34;
答案 4 :(得分:0)
是的,这是完全正确的。您可以使用辅助函数来实现模式,但需要保存一些代码。