对象内部的XMLHttpRequest:如何保持对"this"的引用

Jul*_*ien 8 javascript ajax

我从一个javascript对象里面做了一些Ajax调用:

myObject.prototye = {
  ajax: function() {
    this.foo = 1;

    var req = new XMLHttpRequest();
    req.open('GET', url, true);
    req.onreadystatechange = function (aEvt) {  
      if (req.readyState == 4) {  
        if(req.status == 200)  {
          alert(this.foo); // reference to this is lost
        }
      }
  }
};
Run Code Online (Sandbox Code Playgroud)

在onreadystatechange函数内部,这不再引用主对象,因此我无法访问this.foo.我可以在XMLHttpRequest事件中保留对主对象的引用吗?

CMS*_*CMS 7

最简单的方法通常是将值存储在this局部变量上:

myObject.prototype = {
  ajax: function (url) { // (url argument missing ?)
    var instance = this; // <-- store reference to the `this` value
    this.foo = 1;

    var req = new XMLHttpRequest();
    req.open('GET', url, true);
    req.onreadystatechange = function (aEvt) {  
      if (req.readyState == 4) {  
        if (req.status == 200)  {
          alert(instance.foo); // <-- use the reference
        }
      }
    };
  }
};
Run Code Online (Sandbox Code Playgroud)

我还怀疑你的myObject标识符实际上是一个构造函数(你正在分配一个prototype属性).

如果是这样的话,不要忘记包含正确的constructor属性(因为你要替换整个prototype),这只是一个回到构造函数的引用.

也许这个问题偏离主题,但建议阅读:


Als*_*nde 5

另一个简单的解决方案是将onreadystatechange函数绑定到此.bind- 函数与CMS的答案基本相同(即将值添加到闭包中),但是bind以透明的方式执行:您继续使用this而不是设置instance变量.

Function#bind如果您的代码库不包含以下内容,那么这是一个实现:

Function.prototype.bind = function(obj) {
    var __method = this;
    var args = []; for(var i=1; i<arguments.length; i++) args.push(arguments[i]);
    return function() {
        var args2 = []; for(var i=0; i<arguments.length; i++) args2.push(arguments[i]);
        return __method.apply(obj, args.concat(args2));
    };
}
Run Code Online (Sandbox Code Playgroud)

以下是如何在代码中使用它:

myObject.prototype = {
  ajax: function() {
    this.foo = 1;

    var req = new XMLHttpRequest();
    req.open('GET', url, true);
    req.onreadystatechange = function (aEvt) {  
      if (req.readyState == 4) {  
        if(req.status == 200)  {
          alert(this.foo); // reference to this is *kept*
        }
      }
    }.bind(this) // <- only change
  }
};
Run Code Online (Sandbox Code Playgroud)