OO Javascript回调:我做得对吗?

时间:2012-01-24 07:18:26

标签: javascript jquery callback

背景:我正在构建一个使用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:我选择了最佳答案,但您应该仔细阅读所有答案。每个都为可能的解决方案提供了一些有用的见解。

5 个答案:

答案 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);

当调用thisobj_refmy_callback_method

或者,您可以拉入Underscore.js并使用其bindbindAll。如果你不想要整件事,你总是可以从Underscore.js中抓取bindbindAll

或者,既然你已经在玩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)

我对回调有同样的问题。这就是我处理它的方式。

  • 就像dfsq说的那样,$ .proxy可以帮到你。您不需要任何额外的库,如下划线。
  • Underscore js拥有自己的绑定功能,就像$ .proxy一样。
  • 应用并调用(可在函数上调用的javascript方法)效果很好。

假设我有一个对象:

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)

是的,这是完全正确的。您可以使用辅助函数来实现模式,但需要保存一些代码。