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
,如果我alert(id);
之后
if(responseText.charAt(i)=='.')
我得到了else
中计算出的ID的正确值,但是当我在alert(id);
内$.get
时,id为空""
,则表示{ {1}}函数,append
没有值,如何让这个id的值超出$ .get函数?
答案 0 :(得分:1)
代码流程不是您认为的顺序。
id="";
顺便发生在函数内函数(称为闭包)之前(这应该有助于你的谷歌搜索)。添加打印语句
alert("here 1");
alert("here 2");
在闭包中,在id="";
之前,这应该跳出来。
最简单的修复可能是在闭包中将id
与roomId
交换,因为作为一个简单的字符串或int,该值被完全复制到roomId
,在那里它将是安全的即使id
发生了变化(确切地说,id=...
只更改了引用,因此roomId
引用的值保持不变。)
答案 1 :(得分:1)
那是因为id
在外部闭包中作用域,所以你的内部回调会获得对它在while
循环结束时设置的最后一个值的引用。如果您需要在第二个id
回调中添加$.get()
变量的私有副本,则需要编写
$.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)
称为 immediately invoked function expression 。请注意,此函数返回一个新的函数对象,$.get()
闭包是在另一个中定义的函数。根据定义,闭包可以访问外部函数本地的所有变量。当你提供一个回调以便以后执行到$.get()
时,你实际上正在使用一个闭包:当回调将被执行时(可能在几秒之后),JS引擎将使id
仍然可访问,但是值显然取决于代码的其余部分。
如果您需要存储变量的当前快照以供以后读取,则需要创建一个新的闭包(即新的作用域):我们使用IIFE来实现此目的。 IIFE在之前执行实际HTTP请求被触发(即之前 $.get()
甚至被调用),并且它是回调的最近范围,所以它将用于在执行回调时解析id
引用。
您可以通过弄清楚以下代码段的打印来测试您是否理解这个概念
function inner() {
console.log(i);
}
for (var i = 0; i < 3; i++) {
inner();
setTimeout(inner, 1000);
}