被回调函数中计数器的行为弄糊涂了

Mystified by behavior of a counter in a callback function

本文关键字:弄糊涂 计数器 回调 函数      更新时间:2023-09-26

我一直在尝试修改一个谷歌图表的例子,以便让三个饼图挨着放,尽管我可以让它满意地工作,但我发现我需要减少一个计数器,从逻辑上讲,我觉得这个计数器应该是单独的。如果有人能关注这个工作代码片段,并解释为什么手动递减循环计数器(见注释)是必要的,我将不胜感激,因为没有它,代码就会失败(它只显示一个图表)。

<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      var num_charts = 3;
      var userdata = new Array(num_charts);
      var fn_array = new Array(num_charts);
      for ( var i=0; i<num_charts; i++ )
      {
        userdata[i] = new Array(
          ['Work',      1 + Math.floor(Math.random()*10)],
          ['Eat',       1 + Math.floor(Math.random()*10)],
          ['Commute',   1 + Math.floor(Math.random()*10)],
          ['Watch TV',  1 + Math.floor(Math.random()*10)],
          ['Sleep',     1 + i ]
        );
        fn_array[i] = function() {
          // Need to decrement i for it to work, but why??? The value
          // of i inside this function is one greater than the corresponding 
          // fn_array index, but I don't see why.  
          i--;
          var data = new google.visualization.DataTable();
          data.addColumn('string', 'Task');
          data.addColumn('number', 'Hours per Day');
          data.addRows(userdata[i]);
          var options = {
            width: 400, height: 300,
            title: 'Hello ' + i
          };
          var chart = new google.visualization.PieChart(document.getElementById('chart_div'+i));
          chart.draw(data, options);
        }
      }
      for ( var j=0; j<num_charts; j++ )
        google.setOnLoadCallback(fn_array[j]);
    </script>
  </head>
  <body>
    <span id="chart_div0"></span>
    <span id="chart_div1"></span>
    <span id="chart_div2"></span>
  </body>
</html>

由于在回调中使用相同的变量,回调的每个调用都将具有相同的值,因此在回调中减小其值会导致其值每次都不同。由于javascript是单线程的(不包括webworker),所以这是"好的"。如果你对此感到尴尬,请简单操作:

for ( var i=0; i<num_charts; i++ )
{
  userdata[i] = new Array(
    ['Work',      1 + Math.floor(Math.random()*10)],
    ['Eat',       1 + Math.floor(Math.random()*10)],
    ['Commute',   1 + Math.floor(Math.random()*10)],
    ['Watch TV',  1 + Math.floor(Math.random()*10)],
    ['Sleep',     1 + i ]
  );
  fn_array[i] = (function(local_i){
    return function() {
      // Need to decrement i for it to work, but why??? The value
      // of i inside this function is one greater than the corresponding 
      // fn_array index, but I don't see why.  
      //i--;
      var data = new google.visualization.DataTable();
      data.addColumn('string', 'Task');
      data.addColumn('number', 'Hours per Day');
      //data.addRows(userdata[i]);
      data.addRows(userdata[local_i]);
      var options = {
        width: 400, height: 300,
        //title: 'Hello ' + i
        title: 'Hello ' + local_i
      };
      //var chart = new google.visualization.PieChart(document.getElementById('chart_div'+i));
      var chart = new google.visualization.PieChart(document.getElementById('chart_div'+local_i));
      chart.draw(data, options);
    }
  })(i);
}