如何在XHR请求中保留范围?

时间:2015-05-20 10:18:44

标签: javascript scope xmlhttprequest url-routing

所以我正在构建一个Javascript路由器并构建这样的路由:

route('/user/{name}', 'page', function() {
    this.text = 'User: ' + this.name;
});

函数的作用域是当前路径,所以我可以在这里操作当前路径(this.text是视图所寻找的)。

现在我的下一步是在路线中包含一个XHR请求,如下所示:

route('/user/{name}', 'page', function() {
    this.text = 'Loading';

    var request = new XMLHttpRequest();
    request.open('GET', '/api/user', true);

    request.onreadystatechange = (function() {
        if (this.readyState === 4) {
            if (this.status >= 200 && this.status < 400) {
                var data = JSON.parse(this.responseText);
                // here is the issue: 'this' now refers to
                // the XHR request and not the scope of the router
                this.age = data.age;
                this.gender = data.gender;
            } else {
                this.text = "Error";
            }
        }
    })/* .bind(this); */ // keeping scope like this overwrites the XHR

    request.send();
    request = null;
});

这里的问题是我需要访问XHR范围我路由器的范围。在onreadystatechange末尾使用.bind将覆盖XHR范围,而不是设置它会覆盖路由器的范围。

扫管笏吗?有没有比var that = this;更清洁的东西 - 肯定有办法吗?

2 个答案:

答案 0 :(得分:3)

怎么样:

route('/user/{name}', 'page', function() {
    var routeScope = this;

    request.onreadystatechange = (function() {
        if (this.readyState === 4) {
            if (this.status >= 200 && this.status < 400) {
                console.log(this);
                // "this" is xhr's scope, while 
                console.log(routeScope);
                // routeScope is your router's scope
                // ...
            }
        }
    });
})

编辑:错误,只读你的最后一句......没关系。

答案 1 :(得分:3)

最简单(也是非常明确的方法)是保持对路径范围的引用,如下所示:

var that = this;

您也可以使用.bind()设置范围,并直接从reqest变量访问请求属性。

对于您的示例(使用bind辅助函数,支持旧浏览器):

var bind = function(fn, context) {
    return function() {
        fn.apply(context, arguments);
    };
};

request.onreadystatechange = bind(function() {
  if (request.readyState === 4) {
    if (request.status >= 200 && request.status < 400) {
      var data = JSON.parse(request.responseText);
      this.age = data.age;
      this.gender = data.gender;
    } else {
      this.text = "Error";
    }
  }
}, this);