7

我的问题仍然困扰着我的 js oop - 我确定我做的不好,但我不知道如何做对。

例如,我有这个代码

Auth.prototype.auth = function () {
    var request = new XMLHttpRequest();

    request.open('GET', this.getAuthServerURL() + '/token', true);
    request.send();

    request.onloadend = function () {
      var response = JSON.parse(request.responseText);

      console.log(response);
      if(response.result == 'found') {
        var token = response.token;

        this.setToken(token);
        this.isSigned = true;
      } else {
        console.log('Not logged yet.');
      }
    }
}

问题是我无法从“request.onloadend”函数的上下文访问函数 setToken - 这可能是因为我失去了对“this”的引用。

这个问题的解决方案是什么?我可以以某种方式将“this”变量传递给这个函数的上下文吗?

谢谢!

4

6 回答 6

5

有几种方法可以做到这一点。最直接的就是简单地保存一份你需要的值:

Auth.prototype.auth = function () {
    var request = new XMLHttpRequest();
    var self = this; // save "this" value

    request.open('GET', this.getAuthServerURL() + '/token', true);
    request.send();

    request.onloadend = function () {
      var response = JSON.parse(request.responseText);

      console.log(response);
      if(response.result == 'found') {
        var token = response.token;

        self.setToken(token); // use saved "this" value
        self.isSigned = true;
      } else {
        console.log('Not logged yet.');
      }
    }
}

另一种方法是使用bind

request.onloadend = (function () {
  var response = JSON.parse(request.responseText);

  console.log(response);
  if(response.result == 'found') {
    var token = response.token;

    this.setToken(token); // use saved "this" value
    this.isSigned = true;
  } else {
    console.log('Not logged yet.');
  }
}).bind(this);

第二种方法“更干净”,但存在浏览器兼容性问题(IE < 9 不支持)。

于 2012-07-09T10:44:37.917 回答
2

.bind功能:

Auth.prototype.auth = function () {
    var request = new XMLHttpRequest();

    request.open('GET', this.getAuthServerURL() + '/token', true);
    request.send();

    request.onloadend = function () {
      var response = JSON.parse(request.responseText);

      console.log(response);
      if(response.result == 'found') {
        var token = response.token;

        this.setToken(token);
        this.isSigned = true;
      } else {
        console.log('Not logged yet.');
      }
    }.bind(this); //<-- bound
}
于 2012-07-09T10:45:00.297 回答
1

您可以在外部范围内捕获对它的引用,我使用了 identifier self,但是请随意赋予名称更多语义含义:

var self = this;
request.onloadend = function () {
  ...
  self.setToken(token);
  ...
};
于 2012-07-09T10:44:29.290 回答
1

this回调前捕获:

Auth.prototype.auth = function () {
    var self = this;

    var request = new XMLHttpRequest();

    request.open('GET', this.getAuthServerURL() + '/token', true);
    request.send();

    request.onloadend = function () {
      var response = JSON.parse(request.responseText);

      console.log(response);
      if(response.result == 'found') {
        var token = response.token;

        self.setToken(token);
        self.isSigned = true;
      } else {
        console.log('Not logged yet.');
      }
    }
}
于 2012-07-09T10:44:41.860 回答
0

保存this在回调外部的本地变量中。

Auth.prototype.auth = function () {
    var request = new XMLHttpRequest();
    var _this = this;

    request.open('GET', this.getAuthServerURL() + '/token', true);
    request.send();

    request.onloadend = function () {
      var response = JSON.parse(request.responseText);

      console.log(response);
      if(response.result == 'found') {
        var token = response.token;

        _this.setToken(token);
        _this.isSigned = true;
      } else {
        console.log('Not logged yet.');
      }
    }
}
于 2012-07-09T10:45:11.503 回答
0

你说得很对:回调是用XMLHTTPRequest对象作为上下文(即 的值this)调用的。您需要给您的实例另一个名称,以便您可以在回调范围内访问它:

Auth.prototype.auth = function () {
    var request = new XMLHttpRequest(),
        authInstance = this;

    request.open('GET', this.getAuthServerURL() + '/token', true);
    request.send();

    request.onloadend = function () {
      var response = JSON.parse(request.responseText);

      console.log(response);
      if(response.result == 'found') {
        var token = response.token;

        authInstance.setToken(token);
        authInstance.isSigned = true;
      } else {
        console.log('Not logged yet.');
      }
    }
}

有关为什么这是必要的更多解释,请参见另一个问题的答案。我使用authInstance了而不是self,因为我认为使用描述性变量名称通常很好;您永远不必弄清楚authInstance意味着什么,而self当将来有人(可能是您!)阅读代码时可能会模棱两可。

另一种选择是使用bind,但这可能比这里需要的更复杂。

于 2012-07-09T10:45:14.087 回答