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

时间:2010-06-17 16:48:42

标签: 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();

结果是:

A: my name is IceCube
B: my name is undefined

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

3 个答案:

答案 0 :(得分:5)

this在JavaScript中的工作方式与在C#或Java等其他语言中的工作方式完全不同。函数中this的值完全由函数调用的方式设置,而不是函数定义的位置。更多信息: You Must Remember 'this'

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

foo();

...然后在函数内,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)

因此,要使用正确的“上下文”(this值)调用事件处理程序,您必须采取特殊步骤,如post linked above中所述。

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

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);
    }
}

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

有些原因你可能不想使用这些闭包(内存影响,如果你创建了很多TestObject,因为每个TestObject都有自己的副本每个功能),但由于这已经是你定义对象的方式,因此使用它们几乎没有成本。在这种特殊情况下,我猜测你并没有创造出数以千计的XHR响应者。

答案 1 :(得分: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();

答案 2 :(得分:0)

这是因为您response对象的TestObject功能实际上是而非

您会发现,在JavaScript中,函数并不严格地与对象相关联,就像您在C ++,C#,Java或几乎任何其他语言中看到的那样。相反,函数实际上是单独的对象,它们本身都存在,并且它们具有这个有趣的属性,您可以在任何对象上调用任何函数。

例如:

var obj1 = { Prop1: "Property 1 Value!" };
var obj2 = { Prop2: "Property 2 Value!" };
var myFunc = function() { alert( "Prop1 = " + this.Prop1 + ", Prop2 = " + this.Prop2 ); };

obj1.fn = myFunc; // Assign myFunc to property obj1.fn
obj1.fn();        // Call myFunc with this=obj1

// Similarly for obj2:
obj2.somename = myFunc;
obj2.somename();

输出将是:

Prop1 = Property1 Value!, Prop2 = undefined
Prop1 = undefined, Prop2 = Property 2 Value!

看看我在这里做了什么?函数myFunc本身就存在,不附加到任何特定对象。我将它分配给不同对象的属性。

函数是 - 就像字符串或int一样。我可以这样做:

var str = "Some String";
obj1.someprop = str;

就这么容易我能做到这一点:

var myFunc = function() {}
obj1.someotherprop = myFunc;

现在,当某个对象的某个属性的值是一个函数时,你可以调用该函数,它将在该对象上被称为 - 意味着this将是一个引用该对象。但是,如果您在不使用obj1.前缀的情况下调用相同的函数,则会在该对象上调用 。例如:

var obj1 = {};
obj1.Prop = "Value";
obj1.Func = function() { alert( this.Prop ); }

obj1.Func();        // Displays "Value"

var f = obj1.Func;
f();                // Displays "undefined"

回到原来的问题:问题在于response对象上没有调用TestObject函数。因此,您必须在局部变量中保存对该对象的引用,并使用它而不是this。像这样:

function TestObject()
{
    this.name = "";            //public
    var xhr = null;            //private

    var _this = this;
    var response = function()  //private
    {
        if(xhr.readyState > 3)
        {
            alert("B: my name is " + _this.name);
        }
    }