请帮助我理解“Ajax in Action”中的这段 JavaScript 代码。

发布于 2024-10-26 05:27:54 字数 2449 浏览 1 评论 0原文

我在 Ajax in Action 书中看到了这段代码,有两件事我无法理解(请记住,我刚刚开始 Web 编程,并且仍在尝试了解 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());
    }

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).

  1. 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);"

  2. 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());
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

拥抱我好吗 2024-11-02 05:27:54

ECMA-/Javascript 中的 try/catch 语句创建一个新的 Context。从技术上讲,这类似于 eval 语句,因此类似于 eval Context

当前的作用域链由新创建的作用域链扩展“eval Context”,因此 Context 变量 this 在通过 this.onReadyState( 调用时会指向错误的上下文);

通过调用 net.ContentLoader.onReadyState.call(loader);,作者使用 loaded 的上下文显式调用方法 onReadyState对象(这就是被调用者中的this所引用的内容)。 被调用者是一个被调用者(-context)调用的函数(-context...)。


长话短说,ECMAscripts
.call().apply() 方法允许
你为一个设置一个特定的上下文
调用时的函数。这是
这里是必要的,因为 try/catch
创建一个新的 Context 和值
被调用方法中的 this
错了。


虽然上述说法属实,但在此不负任何责任。问题不是来自 try / catch 的上下文,而是创建的匿名函数的上下文,

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

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

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, because try/catch
creates a new Context and the value of
this 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文