我应该在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的。
答案 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的。