在ajax请求返回后,Javascript对象属性转到undefined

ada*_*das 5 javascript ajax

如果您有一个对象并为其设置属性,则可以在该对象上调用的函数中访问该属性.但是如果你调用一个函数并执行ajax请求,以便从onreadystatechange调用一个不同的函数,那么二级响应函数就无法访问该属性.这有点令人困惑,所以看看我的意思.属性this.name是更改的属性.

//from W3Schools website
function getXHR(){if (window.XMLHttpRequest){return new XMLHttpRequest();}if (window.ActiveXObject){return new ActiveXObject("Microsoft.XMLHTTP");}return null;}

function TestObject()
{
    this.name = "";            //public
    var xhr = null;            //private
    var response = function()  //private
    {
        if(xhr.readyState > 3)
        {
            alert("B: my name is " + this.name);
        }
    }
    this.send = function()     //public
    {
        alert("A: my name is " + this.name);
        if(xhr === null)
        {
            xhr = getXHR();
        }
        var url = "http://google.com";
        xhr.onreadystatechange = response;
        xhr.open("GET", url, true);
        xhr.send(null);          
    }
}
var o = new TestObject();
o.name = "Ice Cube";
o.send();
Run Code Online (Sandbox Code Playgroud)

结果是:

A: my name is IceCube
B: my name is undefined
Run Code Online (Sandbox Code Playgroud)

如果响应是公开的,那么也会发生.如果xhr是公开的,这也会发生.发生了某种情况,因此调用的响应函数无法访问相同的参数.

T.J*_*der 5

thisJavaScript中的工作方式与其他语言(如C#或Java)的工作方式完全不同.this函数内的值完全由函数的调用方式设置,而不是在函数定义的位置.更多信息:你必须记住'这个'.

当以"正常"方式调用函数时:

foo();
Run Code Online (Sandbox Code Playgroud)

...然后在函数内,this将始终引用全局对象(在浏览器上,全局对象是window).对象实例上的一个函数没有任何关系将它"绑定"到该对象.例如:

var obj = {
    name: "Joe",
    speak: function() {
        alert("I'm " + this.name);
    }
};
obj.speak(); // alerts "I'm Joe"
var f = obj.speak;
f();         // alerts "I'm " (this.name is undefined within the call)
Run Code Online (Sandbox Code Playgroud)

因此,要使用正确的"上下文"(this值)调用事件处理程序,您必须采取特殊步骤,如上面链接帖子中所述.

在您的特定情况下,由于您已经为函数定义了闭包,因此您可以使用闭包将关闭的变量轻松处理它:

function TestObject()
{
    var self;

    // Set up a variable referencing `this`
    self = this;

    // From here on out, use it instead of `this`

    self.name = "";            //public
    var xhr = null;            //private
    var response = function()  //private
    {
        if(xhr.readyState > 3)
        {
            alert("B: my name is " + self.name);
        }
    }
    self.send = function()     //public
    {
        alert("A: my name is " + self.name);
        if(xhr === null)
        {
            xhr = getXHR();
        }
        var url = "http://google.com";
        xhr.onreadystatechange = response;
        xhr.open("GET", url, true);
        xhr.send(null);
    }
}
Run Code Online (Sandbox Code Playgroud)

更多关于本文中的闭包,但基本上,这self是有效的,因为该变量可用于TestObject构造函数中定义的函数.您不使用this,因此您不必担心确保以this正确设置的方式调用事件处理程序.

有些原因你可能不想使用那些闭包(内存影响,如果你创建了很多TestObjects,因为每个都有TestObject自己的每个函数的副本),但是因为那已经是你如何定义对象了,所以实际上没有使用它们的成本.在这种特殊情况下,我猜测你并没有创造出数以千计的XHR响应者.


med*_*iev 3

window拥有该onreadystatechange方法,因此在您的回调中,this引用window.

您可以将实例保存在 TestObject 的函数体中,var that = this然后使用that.name。这会将变量绑定到您的回调,以便它会记住自己的实例。

function getXHR(){if (window.XMLHttpRequest){return new XMLHttpRequest();}if (window.ActiveXObject){return new ActiveXObject("Microsoft.XMLHTTP");}return null;}

function TestObject()
{
    var that = this;
    that.name = "";            //public
    var xhr = null;            //private
    var response = function()  //private
    {
        if(xhr.readyState > 3)
        {
            alert("B: my name is " + that.name);
        }
    }
    this.send = function()     //public
    {
        alert("A: my name is " + that.name);
        if(xhr === null)
        {
            xhr = getXHR();
        }
        var url = "http://google.com";
        xhr.onreadystatechange = response;
        xhr.open("GET", url, true);
        xhr.send(null);          
    }
}
var o = new TestObject();
o.name = "Ice Cube";
o.send();
Run Code Online (Sandbox Code Playgroud)