使用回调处理程序调用函数内部的父对象方法

Call parent object method inside function with callback handler

本文关键字:内部 对象 方法 函数 调用 回调 处理 程序      更新时间:2024-02-07

我正在调用ParentObject.doSomething(),它通过inturn调用WebService对象来执行一些ajax调用,一旦ajax调用成功,就会执行回调函数。但是回调函数中的任何父函数都会失败。

我认为这与范围决议有关。我找不到解决这个问题的方法。

有没有更好的架构风格来模块化ajax服务和模型?

我还创建了一个jsfiddle-http://jsfiddle.net/bzKXr/2/

var ParentObject =  {
     doSomething: function(){
         document.write("Inside doSomething <br />");
         var self = this;
         WebServices.firstService("some URL", self.successCallback);
     },
     changeData: function(data){
         //Manipulate data
         document.write("Inside changeData <br />");
     },
     successCallback: function(jsonData){
         document.write("Inside successCallback <br />");
         try {
             //Execution fails at this point. Possibly because of scope resolution
             this.changeData(jsonData);  
         }
         catch (error) {
             console.log(error);
             document.write(error);
         }  
     },
};
var WebServices = {
    firstService: function(url, successCallbackHandler){
        document.write("Inside firstService <br />");
        //Get data using the URL
        //on success call successCallback
        successCallbackHandler("some data");
    }
};

$(document).ready(function() {
    ParentObject.doSomething();
});
​

编写self.successCallback并没有将函数绑定到self,您实际上必须将函数调用为self.successCallback()才能正确绑定上下文。

您可以通过将调用封装在一个闭包中来轻松完成这一操作,该闭包保留对self:的访问权限

doSomething: function(){
     document.write("Inside doSomething <br />");
     var self = this;
     WebServices.firstService("some URL", function() {
        self.successCallback();
     });
 },

或者在ES5中,可以使用.bind(),确保successCallbackthis上下文始终是指定的参数:

doSomething: function(){
     document.write("Inside doSomething <br />");
     WebServices.firstService("some URL", this.successCallback.bind(this));
 },

这里有最漂亮的方法:

WebServices.firstService("some URL", this.successCallback.bind( this ));

但是,它不是跨浏览器的。(阅读:IE8及以下版本无法使用)

这就是为什么jQuery有$.proxy:

WebServices.firstService("some URL", $.proxy( this.successCallback, this ));

调用回调函数时,this无效。在javascript中,如果用foo.bar()调用函数,则this将被设置为foo,但如果您只调用foo(),则会保留先前设置的this,在您的情况下,可能是事件的元素WebService。为了避免这种情况,您必须使用闭包。您可以将this.changeData(jsonData);替换为ParentObject.changeData(jsonData);。闭包意味着函数可以访问定义函数的范围中的变量,因此函数可以访问ParenObject。

一种更优雅的方式可能是:

var ParentObject =  {
    doSomething: function(){
        document.write("Inside doSomething <br />");
        var self = this;
        WebServices.firstService("some URL", function(jsonData) {
            document.write("Inside successCallback <br />");
            self.changeData(jsonData);
        }
    },
    changeData: function(data){
        //Manipulate data
        document.write("Inside changeData <br />");
    }
};

回调函数是直接在doSomething函数中定义的,因此您可以访问其中定义的变量self,并可以调用self.changeData()

另一种可能性是更改

WebServices.firstService("some URL", self.successCallback);

WebServices.firstService("some URL", function(data){ return self.successCallback(data) });

基本问题是,与Python不同,Javascript中的方法Javascript在将它们传递到其他地方或设置另一个变量时就会忘记它们的所有者对象。

如果将this.changeData(jsonData);更改为ParentObject.changeData(jsonData);,它应该可以工作。

错误的原因是,当AJAX调用返回时,this变量不再引用ParentObject

另一种方法是将对this的引用存储在另一个变量中(按照惯例称为that),并将代码更改为that.changeData(jsonData);