Please help me understand this JavaScript code from "Ajax in Action"
I saw this code in Ajax in Action book and there are two things I'm not able to understand (Keep in mind I just started web programming and I'm still trying to understand how JavaScript works).
On line 37 or in function loadXMLDoc, why did the author declared a local variable "var loader=this;" and then used it in the call "net.ContentLoader.onReadyState.call(loader);" instead of just using "net.ContentLoader.onReadyState.call(this);"
Why did the author used "net.ContentLoader.onReadyState.call(loader);", instead of "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()); }
A try/catch
statement in ECMA-/Javascript creates a new Context. Technically, this is similar to an eval
statement and therefore an eval Context
.
The current Scope chain is extended by that newly created "eval Context" and therefore, the Context variable this
, would point to a wrong context when just invoked by this.onReadyState();
.
By calling net.ContentLoader.onReadyState.call(loader);
the author explicitly calls the method onReadyState
with the context of the loaded
object (and that is what this
within the callee is referencing then). A callee is a function (-context...) with was called by a caller (-context).
Long story short, ECMAscripts
.call()
and.apply()
methods allow you to set a specific Context for a function when invoked. This is necessary here, becausetry/catch
creates a new Context and the value ofthis
within the called method would be wrong.
While the above statement is true, it's not responsible here. It's not the Context from try / catch
which is the problem , it's furthermore the Context by the created anonymous function
this.req.onreadystatechange=function(){
net.ContentLoader.onReadyState.call(loader);
}
Using this
within that anonymous method would "again" reference a different Context. That is why the author cached the value from this
in loader
and invokes the method with that cached Context.
精彩评论