使用AJAX澄清Javascript中的闭包

Mer*_*erc 8 javascript ajax closures

我应该在Javascript中正确理解Cloures,但我显然没有......

目前,我正在阅读的文本具有抽象AJAX调用的功能:

function request(url, callback){
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = (function(myxhr){
    return function(){
      callback(myxhr);
    }
  })(xhr);
  xhr.open('GET', url, true);
  xhr.send('');
}
Run Code Online (Sandbox Code Playgroud)

这是我的实际问题:我的大脑拒绝理解为什么这个不起作用:

function request(url, callback){
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = callback(xhr);
  xhr.open('GET', url, true);
  xhr.send('');
}
Run Code Online (Sandbox Code Playgroud)

我的意思是,以"我的"方式,我想象的将是我称之为请求('http:// ...',a_callback).在request()中,创建了一个新的xhr对象,并将其分配给回调...它不会起作用吗?(令人讨厌的)副作用会是什么?从我的(有限的)理解,你需要闭包,例如在一个循环中,你最终可能会引用函数变量的最新值.但是这里......不是"var xhr = ..."确保每次都创建一个新对象吗?

请解释好像我的智商为30(这可能是真的:D)

芝加哥商业交易所.

Poi*_*nty 9

在第一个示例中,您不需要额外的闭包.这样可以正常工作:

function request(url, callback){
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function(){
      callback(xhr);
  };
  xhr.open('GET', url, true);
  xhr.send('');
}
Run Code Online (Sandbox Code Playgroud)

在现代浏览器(或使用polyfill修补的浏览器)中,您也可以这样做:

function request(url, callback){
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = callback.bind(null, xhr);
  xhr.open('GET', url, true);
  xhr.send('');
}
Run Code Online (Sandbox Code Playgroud)

编辑 - 还要注意@Raynos提供的答案.您实际上不需要将XHR对象作为参数传递.

再次编辑 - 为了回应合法评论,你问为什么你原来的想法不起作用:

function request(url, callback){
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = callback(xhr);
  xhr.open('GET', url, true);
  xhr.send('');
}
Run Code Online (Sandbox Code Playgroud)

问题出在这里:

  xhr.onreadystatechange = callback(xhr);
Run Code Online (Sandbox Code Playgroud)

这就分配了从调用回调函数返回onreadystatechange的值.换句话说,不是在状态改变时建立要调用的东西,而是立即进行调用.这个错误很常见,因为它很容易被错误地读出来.但是,任何时候,JavaScript都会看到一个函数引用,后跟一个带括号的参数列表,它被解释为执行函数调用的请求,而不是对未来函数调用的函数包装器的请求.


SLa*_*aks 6

当你写作时xhr.onreadystatechange = callback(xhr),你会callback立即打电话并将结果分配给onreadystatechange.