function updateRoomsList() {
//empty the rooms list
$("#rooms").empty();
//fetch the non-joined rooms, id and name
$.get('JoinPart', {
goal: 5,
userName: $("#userName").html()
}, function (responseText) {
var i = 0;
id = "";
while (i < responseText.length) {
if (responseText.charAt(i) == '.') {
//Now we got the full Id of a room, lets add it
$.get('JoinPart', {
goal: 6,
roomId: id
}, function (responseText) {
roomName = responseText;
$("#rooms").append('<div id="room' + id + '" class="listItem"><span title="Join Room" class="joinButton">+</span><div class="listItemContent">' + roomName + '</div></div>');
});
id = "";
} else {
id = id + responseText.charAt(i);
}
i++;
}
});
}
在这个函数中有一个变量id
,如果我在
if(responseText.charAt(i)=='.')
我得到了在else
中计算的id的正确值,但是当我在$.get
中执行alert(id);
时,id是空的""
,这意味着在append
函数中,id
没有值,我如何才能让这个id在$.get函数之外具有值?
发布于 2012-08-05 15:46:02
这是因为id
的作用域是在外部闭包中,所以内部回调将获得在while
循环末尾设置的最后一个值的引用。如果在第二个$.get()
回调函数中需要id
变量的私有副本,则需要编写
$.get('JoinPart', {goal :6, roomId :id }, (function (id) {
return function (responseText) {
roomName = responseText;
$("#rooms").append('<div>' + id + '</div>');
}
})(id));
当你这样做的时候,你用一个局部变量id
创建了一个新的作用域,它被赋予了id
在当前迭代中的确切值,而不是局部变量id
本身,在循环结束时(或者实际上是在下一次迭代中),它可以是任何东西。
构造(function(arg){})(arg)
称为。请注意,此函数返回一个新的函数对象,即$.get()
所需的对象
闭包是定义在另一个闭包中的函数。根据定义,闭包可以访问外部函数的所有局部变量。当您为稍后执行$.get()
提供一个回调时,您实际上是在使用一个闭包:当执行回调时(可能在几秒钟之后),JS引擎将使id
仍然可访问,但它的值显然取决于代码的其余部分。
如果你需要存储一个变量的当前快照供以后阅读,你需要创建一个新的闭包(即一个新的作用域):我们使用IIFE来实现这个目的。scope是在实际的HTTP请求被触发之前执行的(即在调用$.get()
之前执行),而且它是最近的回调作用域,所以当回调将被执行时,它将用于解析id
引用。
您可以通过确定以下代码段将打印的内容来测试您是否理解了这个概念
function inner() {
console.log(i);
}
for (var i = 0; i < 3; i++) {
inner();
setTimeout(inner, 1000);
}
发布于 2012-08-05 15:40:46
代码流不是你想的那样的顺序。
id="";
在函数内函数之前发生,这被称为闭包(顺便说一句,这应该有助于您的googling搜索)。添加print语句
alert("here 1");
alert("here 2");
在闭包中,在id="";
和这之前应该跳出来。
最简单的修复方法可能是在闭包中将id
与roomId
互换,因为作为简单的字符串或整数,值完全复制到roomId
中,即使id
发生更改,它也是安全的(好的,更准确地说,id=...
只更改引用,因此roomId
引用的值保持不变。)
https://stackoverflow.com/questions/11817701
复制