使用AJAX澄清Javascript中的闭包

时间:2011-10-30 15:23:27

标签: 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('');
}

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

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

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

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

Merc的。

7 个答案:

答案 0 :(得分:9)

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

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

在现代浏览器(或浏览器patched with a polyfill)中,您也可以这样做:

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

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

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

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

问题出在这里:

  xhr.onreadystatechange = callback(xhr);

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

答案 1 :(得分:6)

当您撰写xhr.onreadystatechange = callback(xhr)时,您立即致电callback并将结果分配给onreadystatechange

答案 2 :(得分:1)

在您显示的代码中,您实际上正在调用 callback,因为最后有()

答案 3 :(得分:1)

好问题。函数调用和函数指针之间有一个重要的区别 - 你想给它们一个指向函数的指针(不是真的,它是一个闭包,但这就是我所说的),以便以后可以调用它。如果你做过函数式编程,或者在Lisp系列中使用任何东西,这一点非常重要。

答案 4 :(得分:1)

您无需将xhr传递给回调。

您可以xhr.onreadystatechange = callback;

然后使用this引用回调中的xhr对象。

示例:

xhr.onreadystatechange = function () {
  console.log(this.readystate);
};

免责声明:对于跨浏览器支持的某些价值> _>

答案 5 :(得分:1)

在C语言和函数返回后的大多数其他常用语言中,所有局部变量都不再可访问,因为堆栈帧已被破坏。

在JavaScript中,如果在另一个函数中声明一个函数,那么从您调用的函数返回后,局部变量仍然可以访问。

答案 6 :(得分:0)

我正在回答我自己的问题,因为编辑会混淆一切 - 请原谅我,如果不是这样做的话。

所以......在我的例子中,我实际的意思是:

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

或者,因为我不需要xhr(我可以使用“this”):

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

所以,最后,我是对的...使用封闭(如原始问题所示)是完全浪费时间,对吗?

如果有一个循环,那将是非常重要的,我必须设置几个回调。但是在这种情况下,由于每次调用“request”时都会创建一个新的xhr,并且使用正确的回调设置它,所以实际上不需要有一个闭包..对吗?

Merc的。