XMLHttpRequest对象缺少onreadystatechange()方法。

4
(function (send) {

     XMLHttpRequest.prototype.send = function () {

         console.log(this.onreadystatechange); //null
         send.apply(this, arguments);
     };

})(XMLHttpRequest.prototype.send);

为什么this.onreadystatechange是空的?根据这里的说明,它应该存在且类型为function


它是“null”而不是“undefined”(或引发未定义异常)的事实应该可以解释-它只是尚未设置。 - Ian
那个函数只是用一些日志包装了“send”方法。当调用“send”时,我们无法确定为什么函数是“null”,因为您没有展示使用它的代码。 - Quentin
2个回答

9

onreadystatechange 存在...所以它是 null。如果它不存在,那么它就是 undefined。这完全取决于它是否已经设置过。显然,它已经是一个属性,因为它是 null...如果不是,它就会是 undefined...或者至少 "onreadystatechange" in this 会是 false

下面是一个例子:

var a = new XMLHttpRequest();
a.onreadystatechange = function () {
};
a.send();

您的控制台将记录一个函数

如果您有:

var b = new XMLHttpRequest();
b.send();

您的控制台将记录 null

这是发生的情况的演示:http://jsfiddle.net/3XKx7/

(我已经清楚地省略了发送 AJAX 请求的其他步骤,这只是为了说明)

我并不是试图暗示 nullundefined 之间存在关系 - 我只是想说,在创建新的 XMLHttpRequest 时,onreadystatechange 将在内部设置为 null。无论您是否将其设置为函数,都取决于您。

更新:

创建/发送 XHR 的正常方式如下:

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {    // This and `open` could be flip-flopped
    // whatever
};
xhr.open("POST", url, true);
xhr.send("data=data");

我一直被告知/展示创建新的XMLHttpRequest,然后按任何顺序设置onreadystatechange和调用open,但只有在这两者都完成后,我才应该调用send

因此,如果总是这样做,onreadystatechange(如果实际设置)将不是null,而且会是一个function

由于您提到您正在使用jQuery,我决定测试覆盖send方法,就像您想要的那样,并进行jQuery $.ajax调用(不手动发送XMLHttpRequest)。这是我的测试 - http://jsfiddle.net/3XKx7/1/

不明白为什么onreadystatechange会是null,因为jQuery必须绑定该事件以便知道请求何时完成及其状态。所以我决定查看jQuery源代码。我发现他们调用的顺序是:

xhr.open()
xhr.send()
xhr.onreadystatechange = function () {

};

这意味着当你覆盖 send 方法时,onreadystatechangenull,因为 jQuery 在调用 send 之前没有设置它。我不知道他们的理由是什么...可能是为了防止像你正在做的这样的事情...但我从来没有听说过或看到过这种惯例被使用。
所以你得到它的值为 null 是因为 jQuery 在调用 send 后设置了 onreadystatechange。这意味着当你覆盖 send 并尝试访问 onreadystatechange 属性时,它还没有被设置。
希望这个示例可以帮助你理解:http://jsfiddle.net/dMP6q/16/

我正在尝试使用这个工具拦截jQuery的ajax调用。但是无法弄清为什么它会为空(因为显然jQuery正在使用它)。 - Johan
@Johan 哇,我想我明白你的意思了。是的,它为什么会被设置为“null”没有道理。这是我正在测试的 http://jsfiddle.net/3XKx7/1/ - Ian
@Johan,对我来说有点疯狂,但我查看了jQuery源代码并找到了原因。他们似乎在设置onreadystatechange之前调用了send。我学到的,也一直看到的顺序是.onreadystatechange = function () {};.open().send()。不确定他们是否有理由这样做...也许是为了防止像你所做的那样的事情 :) 我一开始就怀疑这一点,但从未想过他们会真的这样做。但我可以问一下 - 你需要做什么才能使用this.onreadystatechange?只是在覆盖send的同时覆盖它吗? - Ian
1
谢谢您深入了解这个问题 :) 我需要一个全局的ajax监听器来监听不是由我生成的ajax代码(在这种情况下是GWT)。不过要等到周一才能尝试GWT,所以我先尝试了jQuery。 - Johan
1
明白了。非常感谢你的详细解释,Ian。 - Johan
显示剩余3条评论

1

您需要自己进行设置,当状态改变时,该函数将被调用。就像其他事件处理程序一样,比如document.onloadyourelement.onclick等。

经典做法如下:

    var httpRequest = new XMLHttpRequest();
    httpRequest.onreadystatechange = function() {
        if (httpRequest.readyState === 4) {
              if (httpRequest.status === 200) {
                  // use httpRequest.responseText
              }
        }
    };
    httpRequest.open('GET', url);
    httpRequest.send();

随机问题 - 你知道为什么每个人(是的,包括我)总是在回调函数内使用 httpRequest 吗?为什么没有人使用 this?虽然这并不重要,但我只是好奇。我从来没有见过人们使用 this,但我会在普通事件处理程序中看到它。 - Ian
我有时会使用这个,但我发现使用你声明的变量是正常的:你知道它是什么,而你必须知道特定回调的上下文才能使用这个。对于图像的onload也是如此。 - Denys Séguret
没错。我想当设置一个对函数的引用(而不是匿名函数)时,例如 xhr.onreadystatechange = stateChange;,你不能在函数中使用 xhr...你必须使用 this。所以对我来说,总是使用 this 是有意义的,因为它应该始终指向特定的请求。无论如何,我想这并不太重要,我只是想听听你的意见。谢谢 :) - Ian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接