如果您有一个对象并为其设置属性,则可以在该对象上调用的函数中访问该属性。但是如果你调用一个函数并执行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是公开的,这也会发生。发生了一些事情,因此调用的响应函数无法访问相同的参数。
答案 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);
}
}