javascript - 为什么我无法从 onreadystatechange 处理程序内部访问 xhr 对象?

标签 javascript scope xmlhttprequest

编辑:我删除了原始代码,并将其替换为任何人都可以自己运行以重现我的问题的通用代码:

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();
  }
});

Chrome debugger showing closure

注释掉console.log语句,这是对闭包的唯一引用,并且闭包本身消失(使用 V8)。

Closure not present with V8

但是,当您在 Safari 中运行相同的代码(没有引用)时,它使用 WebKit 中的 JavaScriptCore 而不是 V8,并且闭包仍然存在 request已定义,并且调试器按预期工作。

Closure present in Safari

关于javascript - 为什么我无法从 onreadystatechange 处理程序内部访问 xhr 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53448066/

相关文章:

javascript - 为缩小与优化编写 JavaScript

javascript - 如何在此 Google map javascript 中提醒纬度?

javascript - 进度条在 XMLHTTPRequest 中不起作用

angularjs - Angular 2 : PrimeNG - XHR error (404 Not Found)

javascript - 单击 "no submit"按钮形成帖子

javascript - 使用 $state.go 时,是否可以设置 onRouteParms Controller ?

javascript - 在 Javascript 中使用带有 "apply"的局部变量

C++ 静态成员变量作用域

python - UnboundLocalError : local variable referenced before assignment - except it isn't? 全局/局部范围问题

JavaScript:字符串 '//ns1:RunLocatorResponse' 在 Chrome 中包含无法解析的命名空间 - 为什么?