提问人:Merc 提问时间:10/30/2011 更新时间:1/15/2016 访问量:2680
对 Javascript 中使用 AJAX 的闭包的澄清
Clarification on closures in Javascript with AJAX
问:
我应该在 Javascript 中正确理解 Clores,但我显然没有......
目前,我正在阅读的文本具有以下函数来抽象 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('');
}
我的意思是,以“我”的方式,我想象会发生的事情是我调用 say request('http://...', a_callback)。在 request() 中,创建了一个新的 xhr 对象,并将其分配给回调...难道行不通吗?(令人讨厌的)副作用是什么?根据我的(有限的)理解,例如,在一个循环中,你最终可能会引用函数变量的最新值,你需要闭包。但在这里......不是“var xhr=...”确保每次都创建一个新对象?
请解释一下,好像我的智商是 30(这可能是真的:D)
默克。
答:
当你写 时,你会立即调用并将其结果分配给 。xhr.onreadystatechange = callback(xhr)
callback
onreadystatechange
在代码中,您显示您实际上是在调用,因为末尾。callback
()
在第一个示例中,您不需要额外的闭包。这样就可以了:
function request(url, callback){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
callback(xhr);
};
xhr.open('GET', url, true);
xhr.send('');
}
在现代浏览器(或使用 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);
这将立即分配给从调用回调函数返回的值。换句话说,不是在状态更改时建立要调用的内容,而是立即进行调用。这种错误非常普遍,因为很容易读错。但是,每当 JavaScript 看到函数引用后跟括号中的参数列表时,这都会被解释为执行函数调用的请求,而不是对未来函数调用的函数包装器的请求。onreadystatechange
评论
this
问得好。函数调用和指向函数的指针之间有一个重要的区别 - 您希望为他们提供指向函数的指针(不是真的,它是一个闭包,但这就是我所说的),以便他们以后可以调用它。如果你曾经做过函数式编程,或者玩过Lisp家族中的任何内容,这一点非常重要。
您无需传递回调。xhr
你可以做xhr.onreadystatechange = callback;
然后用于引用回调中的对象。this
xhr
例:
xhr.onreadystatechange = function () {
console.log(this.readystate);
};
免責聲明:对于跨浏览器支持的某些价值 >_>
评论
this
在 C 语言和函数返回后的大多数其他常用语言中,由于堆栈帧被销毁,所有局部变量都不再可访问。
在 JavaScript 中,如果在另一个函数中声明一个函数,则局部变量在从调用的函数返回后仍可访问。
我正在回答我自己的问题,因为编辑会混淆一切 - 如果这不是这样做的方法,请原谅我。
所以。。。在我的例子中,我真正想写的是:
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('');
}
所以,最后,我是对的......使用闭包(如原始问题所示)完全是浪费时间,对吧?
如果有一个循环,那会很重要,我必须设置几个回调。但在这种情况下,由于每次调用“请求”时都会创建一个新的 xhr,并且它设置了正确的回调,因此实际上不需要关闭。右?
默克。
评论