Javascript:变量作用域和匿名函数的问题

时间:2014-03-20 18:34:38

标签: javascript scope

我有这个示例代码:

function(){
  var events = [];
  var pages = ["a", "b", "c"];
  for(var pageIndex in pages){
    var pageName = pages[pageIndex];
    var e = function(){
      console.info(pageName);
    };
    events.push(e);
  }
  for(var eventIndex in events){
   console.info("index: " + eventIndex);
   events[eventIndex]();
  }
}

输出:

index: 0 
c 
index: 1 
c 
index: 2 
c 

期望的输出:

index: 0 
a 
index: 1 
b 
index: 2 
c 

这是否有标准做法?

3 个答案:

答案 0 :(得分:1)

欢迎使用javascript中的闭包,你需要将函数包装在IIFE中或立即调用函数表达式,这将创建一个闭包并将状态保存在其范围内:

(function(){

  var events = [];
  var pages = ["a", "b", "c"];

  for(var pageIndex in pages){
    var pageName = pages[pageIndex];
    var e = (function(pageName){
      return function() {console.info(pageName);};
    }(pageName));
    events.push(e);
  }

  for(var eventIndex in events){
   console.info("index: " + eventIndex);
   events[eventIndex]();
  }
}());

将其复制并粘贴到控制台调试器中以进行测试......

答案 1 :(得分:1)

您创建的每个e函数都是一个闭包,它从封闭代码中访问外部变量pageName。它将看到的pageName是函数运行时的值 。因此,在循环结束时pageName"c",这就是所有函数在执行时将使用的内容。

您可以通过以下方式包装函数来解决此问题,这将基本上将pageName的当前值绑定到您创建的函数:

function(){
  var events = [];
  var pages = ["a", "b", "c"];
  for(var pageIndex in pages){
    var pageName = pages[pageIndex];
    var e = (function(data) {
      return function() {
        console.info(data);
      };
    })(pageName);
    events.push(e);
  }
  for(var eventIndex in events){
   console.info("index: " + eventIndex);
   events[eventIndex]();
  }
}

答案 2 :(得分:0)

我找到了答案here。我需要将我的函数包装在另一个函数中。真漂亮。

    Template.index.test = function(){
         var events = [];
         var pages = ["a", "b", "c"];
         for(var pageIndex in pages){
           var pageName = pages[pageIndex];
           var e = function(pageName) {
             return function(){
               console.info(pageName);
             };
           }(pageName);
           events.push(e);
         }
         for(var eventIndex in events){
           console.info("index: " + eventIndex);
           events[eventIndex]();
         }
    }