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 的正确值,但是当我在 $.get
中执行 alert(id);
时> id 为空 ""
,表示在 append
函数中, id
没有值,如何让这个 id 有$.get 函数之外的值?
最佳答案
那是因为 id
的作用域在外部闭包中,因此您的内部回调获取对它在 while
循环结束时设置的最后一个值的引用。如果在第二个 $.get()
回调中需要 id
变量的私有(private)副本,则需要编写
$.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);
}
关于javascript - 无法在 JavaScript 的函数内访问函数中的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11817701/