2015-05-20 30 views
0

所以我建立一个Javascript路由器,建设这样的路线:如何将范围保留在XHR请求中?

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范围,并且不会覆盖路由器的范围。

so wat do?有什么比var that = this;更清洁的 - 肯定有办法吗?

+0

广东话”你只是删除了'this'从'this.age'和'this.gender'? –

+0

为什么不能:'var that = this;'?它可能不是最优雅的方式,但它的工作原理... –

+0

这只是我的问题,是否有一个更清晰的方法来保持范围。 Buuut我猜想没有办法避免它,因为'this'会用'this'进行分类,也许解决方案将是设置默认范围变量的一种方法。不过谢谢@ChrisL和迷宫乐。 – bitten

回答

3

最简单的(和非常明确的方式)是保持这样的参考路线的范围:

var that = this; 

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

并为您的示例(与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); 
+0

谢谢,我想最简洁的方法是更改​​范围变量..我真的很喜欢你的例子(我个人更喜欢保持范围和变量名称一致,所以这就是为什么我沿着这条路线),但它只在Chrome中受支持? – bitten

+0

哦,对不起......我把ES5绑定与来自ES7提议的Object.observe绑定混淆了。这只是一个快速查看http://caniuse.com/#search=bind –

+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 
       // ... 
      } 
     } 
    }); 
}) 

编辑:错了,刚刚看了你的最后一句话......没关系。

+0

也许,我可以做到这一点,并可能会。这主要是跨范围的一致性。不过谢谢。 – bitten