【问题标题】:javascript anonymous function scope behaviorjavascript匿名函数作用域行为
【发布时间】:2011-06-22 03:32:12
【问题描述】:

我有一个遵循这种模式的代码:

a = "abcdefghijklmnopqrstuvwxyz";
m = {};

for(i=0;i<10;i++){
  m[a.charAt(i)] = function(){
      return i;
  };
}

console.log(m.c());

它返回 10。

它为什么要这样做? 我怎样才能让它返回相应的数字?

------- 编辑 -------

感谢您的精彩回复。到目前为止提供的答案适用于上述示例,但我忘了提到我需要传递一个回调函数。考虑到你的建议,我想出了这个:

a = "abcdefghijklmnopqrstuvwxyz";
m = {};

f = function(i) {
    return function(){
        return i;
    }
}

for(i=0;i<10;i++){
    var eval('n') = "hi";
    console.log(n);
    m[a.charAt(i)] = function(fn){
        fn(f(i));
    };
}

m.c(function(a){console.log(a);});

结果与我的直觉一致,即它行不通。有人对此有任何想法吗?

感谢您的帮助

在您的帮助下,我得以开始这个项目: https://github.com/sbussard/python-for-node

请随时按照您的意愿继续贡献。

【问题讨论】:

    标签: javascript node.js scope


    【解决方案1】:

    笼子变量在循环中不改变它们。

    不良行为

    > myFunctions = new Array() 
    [object Array]
    
    for(var i = 0; i < 3; ++i) myFunctions[i] = function() { return i; } 
    
    > myFunctions[0]() 
    3
    
    > myFunctions[1]() 
    3
    
    > myFunctions[2]() 
    3
    

    已修复

    >myFunctions = new Array() 
    [object Array]
    
    function mkFunctionWithCagedValue(value) { 
        return function() { 
            return value;
        };
    } 
    
    > for(var i = 0; i < 3; ++i) myFunctions[i] = mkFunctionWithCagedValue(i) 
    [object Function]
    
    > myFunctions[0]() 
    0
    
    > myFunctions[1]() 
    1
    
    > myFunctions[2]() 
    2
    

    【讨论】:

    • 这似乎可行,但我忘记包含的是我还需要将回调传递给函数。有点像这样:myFunction[0](function(n){alert(n);});
    • @Stephen:嗯……没问题。只需使用function mkFunctionWithCagedValue(value) { return function(f) { f();};} 而不是我示例中稍有不同的行。或者还有更多内容?
    • 也许我不太明白你的意思,因为我的测试让我发现那种东西不起作用。这是我目前得到的: a = "abcdefghijklmnopqrstuvwxyz"; m = {};函数 r(fn,v) { 返回函数() { 返回 fn(v);};} for(i=0;i
    • 此语句更改也会发生相同的错误:for(i=0;i
    • 我真的可以说我学到了关于 javascript 和一般编程的两件不可思议的事情。有用!我认为您刚刚提供的代码实际上可以工作,并且它隐式地将回调函数传递给 r,这真是令人难以置信。我印象深刻!
    【解决方案2】:

    ** 已编辑 **

    在您调用m.c() 时,循环内的变量i 等于10,并且由于它在您的函数中使用,它为每个“索引”返回10。只需保存此变量的副本。例如:

    someFunction = function() {
       alert(i);  // will alert 10 because using i from the loop!
    };
    a = "abcdefghijklmnopqrstuvwxyz";
    m = {};
    
    for(i=0;i<10;i++){
      m[a.charAt(i)] = (function(i, callback) {
         // i is a local copy!
         return function() {
            callback();   // invoke callback function
            return i;
         };
      })(i, someFunction);
    }
    
    console.log(m.c());  // would return 2
    

    【讨论】:

      【解决方案3】:

      函数引用变量i。在函数执行时(在console.log() 行),它会打印出当时值为10 的变量。

      要解决此问题,您需要在每次迭代中创建一个新变量,该变量被分配当前值i。要在每次迭代中获得一个新的变量范围,您可以使用一个附加函数:

      for(i=0;i<10;i++){
        function use_copy() {
          var icopy = i; # a new variable to hold the value of i
          return (function(){
            # original function, now using icopy
            return icopy;
          });
        }
        m[a.charAt(i)] = use_copy();
      }
      

      【讨论】:

      • 每次在循环内创建函数是不必要的。在外面声明接受一个参数 (i) 的函数并设置m[a.charAt(i)] = use_copy(i);
      • 太棒了!有什么方法我也可以传递回调函数吗?
      猜你喜欢
      • 2011-03-11
      • 2011-12-15
      • 2011-12-11
      • 2017-08-13
      • 2011-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多