【问题标题】:for loop with functions [duplicate]带有函数的for循环[重复]
【发布时间】:2015-05-14 14:48:02
【问题描述】:

我有这个(部分)我的网站,我需要从 TVDB/MovieDB API 获取数据。我需要一集的截图,所以我使用了

theMovieDb.tvEpisodes.getImages({
"id": showID,
"season_number": season_number,
"episode_number": episode_number
}, function(data){}, function(error){})

我需要执行 6 次,因为我需要包含 6 个不同情节的 6 张图像。

for(var i = 0; i < 7; i++){

}

但问题是,如果我现在在function(data){} 部分内询问console.log(i),它会记录6,六次...
我做错了什么?

这是完整的代码,包含来自其他函数等的变量...

      for(var i = 0; i < 6; i++) {
    iF = i;
    u = i + 1
    epLen = data.episodes[data.episodes.length - 1 - i]
  var thies = "<center><span style='font-family: Arial'>" + epLen.season_number + 'x' + epLen.episode_number + ": <br>" + epLen.name + "<br>"+ epLen.air_date +"</span></center>";
  var thisId = "recent" + u.toString();
  var text = thies;
  document.getElementById(thisId).innerHTML = text;
  theMovieDb.tvEpisodes.getImages({"id": showID, "season_number": epLen.season_number, "episode_number": epLen.episode_number},
  function(data){
    var data = JSON.parse(data);
    window.still = data.stills[0].file_path;
    console.log(window.still);
    console.log(iF); // logs 5
    console.log(i); // logs 6
},
  function(error){})
  //alert(i)

  //var still = window.still;
  //console.log(still);
  //var epStil = "https://image.tmdb.org/t/p/original" + still.stills[0].file_path;
  //var epStill = "url(" + epStil + ")";
  //document.getElementsByClassName("recent")[i].style.backgroundImage = epStill;

}

编辑
我找到了解决办法,由于被标记为重复,我不能再回答了,所以我将它贴在这里:

epStilArray = [];
  for(var i = 0; i < 6; i++) {
    iF = i;
    u = i + 1
    epLen = data.episodes[data.episodes.length - 1 - i]
  var thies = "<center><span style='font-family: Arial'>" + epLen.season_number + 'x' + epLen.episode_number + ": <br>" + epLen.name + "<br>"+ epLen.air_date +"</span></center>";
  var thisId = "recent" + u.toString();
  var text = thies;
  document.getElementById(thisId).innerHTML = text;
  theMovieDb.tvEpisodes.getImages({"id": showID, "season_number": epLen.season_number, "episode_number": epLen.episode_number},
  function(data){
    var data = JSON.parse(data);
    still = data.stills[0].file_path;
    var epStil = "https://image.tmdb.org/t/p/original" + still;
    var epStil = "url(" + epStil + ")";
    epStilArray.push(epStil);
    console.log(epStilArray);
    document.getElementsByClassName("recent")[epStilArray.length - 1].style.backgroundImage = epStil;
},
  function(error){})
}

【问题讨论】:

  • 你能告诉我们你的实际for循环吗?
  • 您的代码可能运行良好。 console.log() 语句是异步执行的,所以在循环结束之前它不会第一次运行
  • @StephenThomas 但我的代码的其他部分需要i,这也需要等待吗?

标签: javascript function api loops


【解决方案1】:

这是一个很好的例子,您可以使用 JavaScript 闭包来确保内联函数的每个实例都可以访问 i 的不同值。

这样做的一种方法是将代码包装在立即调用的函数表达式 (IIFE) 中,并在与该函数表达式的范围相关的不同变量中捕获所需变量的副本。这可以以(function(){ var iCopy = i; /*your code here*/})();(function(iCopy){ /*your code here*/})(i); 的格式完成

将复制的变量设置在 IIFE 中自己的行中:

for(var i = 0; i < 6; i++) {
    ...
    (function(){
        var iCopy = i; // i is copied to iCopy
        theMovieDb.tvEpisodes.getImages({},
            function(data){
                ...
                console.log(iCopy); 
            }, function(error){});
    })(); // this IIFE has its own scope capturing a copy of the variable i
 }

或者,将变量作为参数传递给 IIFE:

for(var i = 0; i < 6; i++) {
    ...
    (function(iCopy){ // i is copied to iCopy
        theMovieDb.tvEpisodes.getImages({},
            function(data){
                ...
                console.log(iCopy); 
            }, function(error){});
    })(i); // this IIFE has its own scope capturing a copy of the variable i as a parameter
}

还请注意,您不必更改复制变量的名称;为了清楚起见,我只是在上面的示例中这样做了。如果不同作用域中的两个变量共享相同的名称,则代码将引用更直接(最内层)的作用域。因此,以下代码也可以工作:

for(var i = 0; i < 6; i++) {
    ...
    (function(i){ // i is copied to i
        theMovieDb.tvEpisodes.getImages({},
            function(data){
                ...
                console.log(i); 
            }, function(error){});
    })(i); // this IIFE has its own scope capturing a copy of the variable i as a parameter
}

【讨论】:

    【解决方案2】:

    你有一个关闭问题。有许多资源可以了解更多关于 js 中的闭包的信息。 Here is the JSLint entry on it specific to loops.

    您可以通过创建 IIFE 并传入计数器的副本来解决此问题。

    for(var i = 0; i < 6; i++) {
        (function (iCopy) {
            iF = iCopy;
            u = iCopy + 1
            epLen = data.episodes[data.episodes.length - 1 - iCopy]
            var thies = "<center><span style='font-family: Arial'>" + epLen.season_number + 'x' + epLen.episode_number + ": <br>" + epLen.name + "<br>"+ epLen.air_date +"</span></center>";
            var thisId = "recent" + u.toString();
            var text = thies;
            document.getElementById(thisId).innerHTML = text;
            theMovieDb.tvEpisodes.getImages({"id": showID, "season_number": epLen.season_number, "episode_number": epLen.episode_number},
                function(data){
                    var data = JSON.parse(data);
                    window.still = data.stills[0].file_path;
                    console.log(window.still);
                    console.log(iF); // logs 5
                    console.log(iCopy); // logs 6
                },
                function(error){})
        }(i));
    }
    

    【讨论】:

    • 我试过了,这是我的日志:[Log] /tNtdHIhLwQurJ4430n7scKNjPCg.jpg (index.html, line 288) [Log] 5 (index.html, line 289) [Log] 6 (index.html, line 290) [Log] /z2E4Rq7D5TmAdzS9D6Wije3sGI3.jpg (index.html, line 288) [Log] 5 (index.html, line 289) [Log] 6 (index.html, line 290) [Log] /3cEVM4peZW2r2HiKVzxDjmBLJxD.jpg (index.html, line 288) //etc 所以仍然只有 5 和 6...
    【解决方案3】:

    为了隔离问题,我刚刚将函数调用放入循环中,它运行良好。这个问题确实可能与异步工作流和闭包有关,所以如果对您来说订单很重要,只需在闭包中传递变量“i”。

    例如,下一个代码日志: i = 0. i = 1. i = 2. i = 3. i = 4. i = 5

    function myFunction(f) {f()}
    
    for (var i = 0; i < 6; i++) {
        myFunction(function() { console.log('i = ' + i); })
    }
    

    在您的问题中,我还看到您在不同的范围内使用“var i”和“iF”w/o“var”。

    【讨论】:

    • 您的具体问题/问题是什么?你想做什么?该函数的预期输出是什么?请编辑您的帖子并详细说明。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多