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

Please help me understand this JavaScript code from “Ajax in Action”

我在Ajax in Action书中看到了这个代码,有两件事我无法理解(请记住,我刚刚开始进行Web编程,而我仍然试图理解JavaScript是如何工作的)。

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

  • 为什么作者使用"net.ContentLoader.onReadyState.call(loader);"而不是"this.onReadyState();"

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
        /*
        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!"
            +"

    readyState:"
    +this.req.readyState
            +"
    status:"
    +this.req.status
            +"
    headers:"
    +this.req.getAllResponseHeaders());
        }

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

    当前的Scope链由新创建的"eval Context"扩展,因此,当由this.onReadyState();调用时,Context变量this将指向错误的上下文。

    通过调用net.ContentLoader.onReadyState.call(loader);,作者使用loaded对象的上下文显式调用方法onReadyState(这就是被调用者中的this然后引用)。被调用者是一个函数(-context ...),由调用者调用(-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.

    虽然上述陈述属实,但在此不承担任何责任。它不是来自try / catch的上下文,这是问题,它是创建的匿名函数的上下文

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

    在该匿名方法中使用this将"再次"引用不同的Context。这就是作者在loader中缓存this中的值并使用该缓存的Context调用该方法的原因。