编辑:我删除了原始代码,并将其替换为任何人都可以自己运行以重现我的问题的通用代码:
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();
}
});
对我来说,在那个匿名函数中 debugger
声明是,request
神秘地没有定义,尝试访问它是 ReferenceError
。这真的让我很困惑。
这是奇怪的部分。如果我创建一个在顶层定义的一次性变量,并设置 throwaway = request;
创建request
后立即对象,然后在 onreadystatechange
内处理程序throwaway
已定义,一切正常,即使 request
未定义。
我刚刚测试了它,我也可以通过 this
访问它正如预期的那样,在调试器语句处。是什么赋予了?为什么是request
没有定义?
最佳答案
引用request
是对内部函数周围执行上下文的引用,内部函数是实现闭包一部分的堆分配结构,并且会受到垃圾收集。
如上所述here ,如果没有引用,V8 JavaScript 引擎(Chrome 和 Node.JS 等应用程序使用该引擎来实现 JavaScript)不会创建闭包。 (这是一项优化。)因此,当您打开调试器时,对 request
的引用已丢失,这就是为什么您会得到 ReferenceError
而不是undefined
。请注意,Safari 11 中的行为有所不同,它使用 WebKit 中的 JavaScriptCore(而不是 V8)来实现 JavaScript。
如果添加对 request
的引用在内部函数内部,然后 V8 将创建闭包,您将可以在调试器内部访问 in 。
示例
在 Chrome 中运行此代码(或者像我一样在 Opera 中运行,它也使用 V8),您将看到作用域链中列出的闭包。
var StripeCheckout = {
configure: function(obj) {
return obj.token();
}
};
StripeCheckout.configure({
token: function(token) {
var request = new XMLHttpRequest();
request.open('POST', 'https://jsonplaceholder.typicode.com/posts');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
// include the console.log statement
// and everything works as expected.
console.log('req.rs:', request.readyState);
debugger; // right here is the problem
};
request.send();
}
});
注释掉console.log
语句,这是对闭包的唯一引用,并且闭包本身消失(使用 V8)。
但是,当您在 Safari 中运行相同的代码(没有引用)时,它使用 WebKit 中的 JavaScriptCore 而不是 V8,并且闭包仍然存在 request
已定义,并且调试器按预期工作。
关于javascript - 为什么我无法从 onreadystatechange 处理程序内部访问 xhr 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53448066/