javascript中奇怪的变量范围

时间:2013-06-19 17:28:41

标签: javascript jquery facebook-javascript-sdk

所以我用javascript编写了这段代码:

// Additional initialization code such as adding Event Listeners goes here
            FB.api('593959083958735/albums', function(response) {
                if(!response || response.error) {
                    // render error
                    alert("Noo!!");
                } else {
                    // render photos
                    for(i=0; i<response.data.length; i++){
                        var albumName = response.data[i].name;
                        var albumCover = response.data[i].cover_photo;
                        var albumId = response.data[i].id;
                        console.log(albumName);
                        FB.api( albumCover, function(response) {
                            if(!response || response.error) {
                                // render error
                                alert("Noo!!");
                            } else {
                               // render photos
                               $("ul").append('<li>'+
                                    '<a href="testFile.HTML" data-transition="slidedown">'+
                                    '<img src= "' + response.picture + '"  />'+
                                     '<h2>' + albumName + '</h2>'+
                                     '<p> Test Paragraph</p>'+
                                     '</a>'+
                                     '</li>')
                                .listview('refresh');
                            }
                        });                                 
                    }
                }
            });

我正在使用facebooks javascript API,将facebook页面的相册导入我的jquery移动页面并将它们放入listView。如您所见,我动态创建listView。 listView的缩略图为专辑coverPhoto和标题,专辑名称。

然而,这里有些可怕的错误。可以看到上面代码的结果here

缩略图都正确但相册名称错误。在每个单元格中,我获得最后一个专辑名称。当我看到我的代码中的console.log(albumName)时,我得到的所有名称都是正确的。但在第二次调用FB.api时,"albumName"变量只保留最后一个专辑名称。

知道这里发生了什么吗?它确实让我疯狂......

2 个答案:

答案 0 :(得分:2)

看起来你有着名的i for loop问题,你只能引用i。

                for (var i = 0; i < response.data.length; i++) {  //added the var here
                    (function (i) {  //created a function
                        var albumName = response.data[i].name;
                        var albumCover = response.data[i].cover_photo;
                        var albumId = response.data[i].id;
                        console.log(albumName);
                        FB.api(albumCover, function (response) {
                            if (!response || response.error) {
                                // render error
                                alert("Noo!!");
                            } else {
                                // render photos
                                $("ul").append('<li>' +
                                    '<a href="testFile.HTML" data-transition="slidedown">' +
                                    '<img src= "' + response.picture + '"  />' +
                                    '<h2>' + albumName + '</h2>' +
                                    '<p> Test Paragraph</p>' +
                                    '</a>' +
                                    '</li>')
                                    .listview('refresh');
                            }
                        });
                    })(i);  //call the function with i
                }

答案 1 :(得分:2)

问题实际上不是i,而是albumName

大多数JavaScript引擎都非常宽容,允许您多次使用var关键字声明相同的变量。这就是你在这里做的事情。重要的是要注意 for关键字不会引入新范围;因此,当您(重新)在循环中声明每个变量(albumNamealbumCoveralbumId)时,您将覆盖先前存储在同一变量中的值。

这回过头来咬你,因为你传递给FB.api的回调关闭了这些局部变量,并且(显然)异步执行。当回调实际运行时,for循环已完成,并且这些变量都设置为它们的最后一个值。

当然,例外是albumCover,正如您已经观察到的那样(您说缩略图都是正确的)。那是因为您同步将此值传递给FB.api;即,你在循环中传递 ,因此它不会被关闭。

为了更好地理解JavaScript中的闭包,请参阅How do JavaScript closures work?

要明确:epascarello's answer应该为您解决问题。在匿名函数中包含逻辑引入一个新范围(一种可用于各种场景的有用技巧),因此albumName等的值将被关闭每次回调都不同。我只是想指出,导致问题的不是i本身(因为你的回调根本没有关闭i)。

相关问题