Javascript 为什么可以';我不能从onreadystatechange处理程序内部访问xhr对象吗?
编辑:我已删除了原始代码,并将其替换为通用代码,任何人都可以自行运行以重现我的问题:Javascript 为什么可以';我不能从onreadystatechange处理程序内部访问xhr对象吗?,javascript,scope,xmlhttprequest,Javascript,Scope,Xmlhttprequest,编辑:我已删除了原始代码,并将其替换为通用代码,任何人都可以自行运行以重现我的问题: var StripeCheckout = { configure: function(obj){ obj.token(); } }; StripeCheckout.configure({ token: function(token) { var request = new XMLHttpRequest(); request.open('P
var StripeCheckout = {
configure: function(obj){
obj.token();
}
};
StripeCheckout.configure({
token: function(token) {
var request = new XMLHttpRequest();
request.open('POST', 'http://localhost:3000/process-order');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
debugger; // right here is the problem
};
request.send();
}
});
对我来说,在调试器
语句所在的匿名函数中,请求
神秘地没有定义,试图访问它是一个引用错误
。这真让我迷惑
这是奇怪的部分。如果我创建了一个在顶层定义的throwaway变量,并设置throwaway=request代码>在创建请求
对象之后,在onreadystatechange
处理程序中定义了一次性
,并且一切正常,即使未定义请求
我刚刚对它进行了测试,我还可以在调试器语句处以this
的形式访问它,正如预期的那样。有什么好处?为什么未定义request
?对request
的引用是对围绕内部函数的执行上下文的引用,内部函数是实现闭包的一部分的堆分配结构,需要进行垃圾收集
如前所述,如果没有引用,V8 JavaScript引擎(Chrome和Node.JS以及其他应用程序使用它来实现JavaScript)不会创建闭包。(这是一个优化。)因此,当您点击调试器时,对请求
的引用已经丢失,这就是为什么您会得到引用错误
,而不是未定义
。注意,Safari 11中的行为不同,它使用WebKit(而不是V8)中的JavaScriptCore来实现JavaScript
如果在内部函数中添加对request
的引用,那么闭包将由V8创建,并且您可以访问调试器中的
例子
在Chrome中运行这段代码(或者像我在Opera中一样,Opera也使用V8),您将看到范围链中列出了一个闭包
var StripeCheckout={
配置:功能(obj){
返回obj.token();
}
};
StripeCheckout.configure({
令牌:函数(令牌){
var request=new XMLHttpRequest();
请求打开('POST','https://jsonplaceholder.typicode.com/posts');
setRequestHeader('Content-Type','application/json;charset=UTF-8');
request.onreadystatechange=函数(){
//包括console.log语句
//一切都按预期进行。
log('req.rs:',request.readyState);
调试器;//问题就在这里
};
request.send();
}
});
注释掉console.log
语句,这是对闭包的唯一引用,闭包本身就会消失(使用V8)
但是,当您在Safari中运行相同的代码(没有引用)时,它使用WebKit中的JavaScriptCore而不是V8,并且在定义了request
的情况下仍然存在闭包,并且调试器按预期工作
JavaScript函数是闭包。它们捕获周围范围内的变量,这些变量是它们工作所需的,但仅此而已。由于在函数的实际代码中没有引用请求
,因此JavaScript不会捕获它,因为函数似乎不需要它。如果包含引用请求的代码
,则它将被定义为:
var-request=new-XMLHttpRequest();
请求打开('POST','http://localhost:3000/process-订单);;
setRequestHeader('Content-Type','application/json;charset=UTF-8');
request.onreadystatechange=函数(){
log(request.toString());
调试器;
};
request.send()代码>如果替换调试器会发生什么代码>带有console.log(响应)代码>?不要总是信任调试器。相信你所知道的语言。我见过很多情况,例如,边缘调试器会说谎关于状态。完全重复