2011-03-23 56 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