Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/458.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 为什么可以';我不能从onreadystatechange处理程序内部访问xhr对象吗?_Javascript_Scope_Xmlhttprequest - Fatal编程技术网

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(响应)?不要总是信任调试器。相信你所知道的语言。我见过很多情况,例如,边缘调试器会说谎关于状态。完全重复