无法在JavaScript中的函数内访问函数中的变量

时间:2012-08-05 15:34:47

标签: javascript global-variables

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函数?

2 个答案:

答案 0 :(得分:1)

代码流程不是您认为的顺序。

            id="";

顺便发生在函数内函数(称为闭包)之前(这应该有助于你的谷歌搜索)。添加打印语句

alert("here 1");
alert("here 2"); 

在闭包中,在id="";之前,这应该跳出来。

最简单的修复可能是在闭包中将idroomId交换,因为作为一个简单的字符串或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);
}​