封装ajax调用失败可能是因为对象可见性



我有这段应该在Firefox 3.6上工作的代码。问题是这个变量。应该定义为STEP2并在STEP3上使用的xmlhttp就像STEP2和STEP3上的代码位于不同的变量环境中一样,尽管我希望server_request和callback_function中的两种用法指向下面定义的query_request_manager超对象中的相同成员对象。我还创建了类似的代码,在服务器响应时没有异步回调,按照我的意图工作。

function Generic_server_request(server_location, server_file, client_callback_function)
{
    this.server_location = server_location;
    this.server_file = server_file;
    this.query_parameters = "";
    this.client_callback_function = client_callback_function;
    this.xmlhttp = undefined;
} // STEP1 should create xmlhttp as undefined
Generic_server_request.prototype.callback_function = function ()
{
    if (this.xmlhttp.readyState === 4 // STEP3 ERROR this.xmlhttp is undefined
    // I expected it to be the object defined at STEP2
    // but it's not so according to firebug
    // similar code without asynchronous callback
    // seems to work as I expect it to : no undefined error
    && this.xmlhttp.status === 200)
    {
        this.client_callback_function(
        this.xmlhttp.responseText);
    }
    else if (this.xmlhttp.status !== 200 || (this.xmlhttp.status === 200 && this.xmlhttp.readyState !== 2 && this.xmlhttp.readyState !== 3))
    {
        alert("readystate " + this.xmlhttp.readyState + " status " + this.xmlhttp.status);
    }
};
Generic_server_request.prototype.server_request = function ()
{
    this.xmlhttp = new XMLHttpRequest(); // STEP2 xmlhttp defined for use
    this.xmlhttp.onreadystatechange = this.callback_function; // server callback to prototype.callback
    this.xmlhttp.open("GET", this.server_location + this.server_file + this.query_parameters, true);
    this.xmlhttp.send();
};
Generic_server_request.prototype.set_query_parameters = function (query_parameters)
{
    this.query_parameters = query_parameters;
};
var query_request_manager;
function do_querry()
{
    server_querry("test");
}
function server_querry(input)
{
    if (query_request_manager === undefined)
    {
        query_request_manager = new Generic_server_request( // the definition
        "http://localhost/cgi-bin/", "querry_handler.php", status_text);
    }
    query_request_manager.set_query_parameters("?input=" + input);
    query_request_manager.server_request();
} // the usage
//end javascript
<input type="button" value="Enter" onclick="do_querry();" />

问题是这个分配:

this.xmlhttp.onreadystatechange = this.callback_function;

赋值由this定义的函数。Callback_function绑定到onreadystatechange,但没有将其范围绑定到query_request_manager(这意味着在执行回调时,它将绑定到全局范围,而不是您想要的对象)。要解决这个问题,可以使用委托函数:

this.xmlhttp.onreadystatechange = (function () {
    var me = this;
    return function () {
       return me.callback_function.apply(me, arguments);
    }
}).call(this);

试试这个:

var Generic_server_request = function(server_location, server_file, client_callback_function){
  this.server_location = server_location;
  this.server_file = server_file;
  this.query_parameters = "";
  this.client_callback_function = client_callback_function;
  this.xmlhttp = undefined; // STEP1 should create xmlhttp as undefined
}
Generic_server_request.prototype.callback_function = function(){
  if(this.xmlhttp.readyState === 4 && this.xmlhttp.status === 200){ // STEP3 ERROR this.xmlhttp is undefined
    // I expected it to be the object defined at STEP2
    // but it's not so according to firebug
    // similar code without asynchronous callback
    // seems to work as I expect it to : no undefined error
    this.client_callback_function(this.xmlhttp.responseText);
  } else if(this.xmlhttp.status!==200 || (this.xmlhttp.status===200 && this.xmlhttp.readyState!==2 && this.xmlhttp.readyState!==3)){
    alert("readystate " + this.xmlhttp.readyState + " status " + this.xmlhttp.status);
  }
};
Generic_server_request.prototype.server_request=function(){
  this.xmlhttp = new XMLHttpRequest(); // STEP2 xmlhttp defined for use
  this.xmlhttp.onreadystatechange = this.callback_function; // server callback to prototype.callback
  this.xmlhttp.open("GET", this.server_location + this.server_file + this.query_parameters, true);
  this.xmlhttp.send();
};
Generic_server_request.prototype.set_query_parameters = function(query_parameters){
  this.query_parameters = query_parameters;
};
var query_request_manager; 
function do_querry(){
  server_querry("test");
}
function server_querry(input){
  if(query_request_manager === undefined){
    query_request_manager = new Generic_server_request("http://localhost/cgi-bin/", "querry_handler.php", status_text);
  }
  query_request_manager.set_query_parameters("?input=" + input);
  query_request_manager.server_request();
}

<input type="button" value="Enter" onclick="do_querry();" />

最新更新