2011-03-23 59 views
2

我在Ajax in Action书中看到了这段代码,并且有两件事情我无法理解(请记住,我刚刚开始了web编程,而且我仍然试图了解JavaScript是如何工作的)。请帮我理解“Ajax in Action”中的这段JavaScript代码

  1. 在第37行或函数loadXMLDoc中,为什么作者声明了一个局部变量“var loader = this;”然后用它在调用“net.ContentLoader.onReadyState.call(loader);”而不是仅仅使用“net.ContentLoader.onReadyState.call(this);”

  2. 为什么作者使用“net.ContentLoader.onReadyState.call(loader);”,而不是“this.onReadyState();”

 
    /* 
    url-loading object and a request queue built on top of it 
    */ 

    /* namespacing object */ 
    var net=new Object(); 

    net.READY_STATE_UNINITIALIZED=0; 
    net.READY_STATE_LOADING=1; 
    net.READY_STATE_LOADED=2; 
    net.READY_STATE_INTERACTIVE=3; 
    net.READY_STATE_COMPLETE=4; 


    /*--- content loader object for cross-browser requests ---*/ 
    net.ContentLoader=function(url,onload,onerror,method,params,contentType){ 
     this.req=null; 
     this.onload=onload; 
     this.onerror=(onerror) ? onerror : this.defaultError; 
     this.loadXMLDoc(url,method,params,contentType); 
    } 

    net.ContentLoader.prototype.loadXMLDoc=function(url,method,params,contentType){ 
     if (!method){ 
     method="GET"; 
     } 
     if (!contentType && method=="POST"){ 
     contentType='application/x-www-form-urlencoded'; 
     } 
     if (window.XMLHttpRequest){ 
     this.req=new XMLHttpRequest(); 
     } else if (window.ActiveXObject){ 
     this.req=new ActiveXObject("Microsoft.XMLHTTP"); 
     } 
     if (this.req){ 
     try{ 
      var loader=this; 
      this.req.onreadystatechange=function(){ 
      net.ContentLoader.onReadyState.call(loader); 
      } 
      this.req.open(method,url,true); 
      if (contentType){ 
      this.req.setRequestHeader('Content-Type', contentType); 
      } 
      this.req.send(params); 
     }catch (err){ 
      this.onerror.call(this); 
     } 
     } 
    } 


    net.ContentLoader.onReadyState=function(){ 
     var req=this.req; 
     var ready=req.readyState; 
     var httpStatus=req.status; 
     if (ready==net.READY_STATE_COMPLETE){ 
     if (httpStatus==200 || httpStatus==0){ 
      this.onload.call(this); 
     }else{ 
      this.onerror.call(this); 
     } 
     } 
    } 

    net.ContentLoader.prototype.defaultError=function(){ 
     alert("error fetching data!" 
     +"\n\nreadyState:"+this.req.readyState 
     +"\nstatus: "+this.req.status 
     +"\nheaders: "+this.req.getAllResponseHeaders()); 
    } 

回答

2

ECMA-/ JavaScript的一个 try/catch语句创建一个新的 语境。从技术上讲,这与 eval声明相似,因此是 eval Context

当前作用域链由新创建的“EVAL语境”,因此,该背景信息可变this,当只是通过this.onReadyState();调用将指向错误的上下文扩展。

通过调用 net.ContentLoader.onReadyState.call(loader);笔者明确调用该方法 onReadyStateloaded对象的情况下(这是什么 被叫this被引用即可)。 A callee是一个函数(-context ...),被 调用者(-context)调用。


长话短说,ECMAscripts .call().apply()方法允许 调用时,您可以设置特定的上下文的 功能。这里需要的是 ,因为try/catch 创建了一个新的上下文,并且 this的值在被调用的方法内会出错 是错误的。


虽然上述声明是真实的,它不负责这里。这不是从try/catch语境这是问题,这还通过创建匿名函数

this.req.onreadystatechange=function(){ 
    net.ContentLoader.onReadyState.call(loader); 
} 

匿名方法中使用this会“再次”引用一个不同的上下文语境。这就是为什么作者将this中的值缓存在loader中,并使用该缓存的上下文调用该方法。

+0

但是在这里调用“net.ContentLoader.onReadyState.call(loader);” loader与try/catch块中的相同,即它仍然指向try块后扩展的上下文。对于你所说的话,他不应该在try块之前移动loader变量的创建吗? – nik 2011-03-23 15:28:16

+0

@NikhilRathod:我更新了答案。作者实际上应该在'try/catch'之前移动'this value'的存储。它仍然在这里工作,因为范围链查找无论如何都会解决该方法。 – jAndy 2011-03-23 15:34:20

+0

@jAndy:那他为什么要创建一个匿名函数? “this.req.onreadystatechange = net.ContentLoader.onReadyState.call(this)”中出现了什么问题? – nik 2011-03-23 15:51:45