Javascript闭包?

Javascript闭包?,javascript,closures,Javascript,Closures,方法#1 上述方法用于将数组对象转换为单个函数,这些函数在执行时返回特定的数组对象。想知道为什么方法1有效而方法2无效。在方法2中有两个问题: 返回的是键名a,而不是数组值ar[a]。也就是说,而不是返回a您想要返回ar[a] 函数将始终引用循环通过的最后一个值,因为它引用相同的范围对象。要创建一个新的范围对象,您需要一个闭包、一个带有块的或一个绑定函数 结束时: for(var a in ar) { var O = (function(val) { return functio

方法#1

上述方法用于将数组对象转换为单个函数,这些函数在执行时返回特定的数组对象。想知道为什么方法1有效而方法2无效。

在方法2中有两个问题:

  • 返回的是键名
    a
    ,而不是数组值
    ar[a]
    。也就是说,而不是
    返回a
    您想要
    返回ar[a]

  • 函数将始终引用循环通过的最后一个值,因为它引用相同的范围对象。要创建一个新的范围对象,您需要一个闭包、一个带有块的
    或一个绑定函数

  • 结束时:

    for(var a in ar) { 
      var O = (function(val) { 
        return function() { 
          return val; 
         }
      })(ar[a]);
      alStr.push(O); 
    }
    
    使用带有
    块的

    for(var a in ar) { 
      with({val: ar[a]}) {
        alStr.push(function() { 
          return val; 
         });
      }
    } 
    
    使用绑定函数:

    for(var a in ar) { 
      var O = function(x) { return x; };
      alStr.push(O.bind(null, arr[a]));
    } 
    

    彼得·奥尔森是对的。但是,更现代(正确的?)的方法是使用
    function.bind(obj,val)
    。最近引入的
    function.bind
    允许您在特定上下文中按值传递变量。阅读更多

    你可以这样写:

    function transform(ar) {
        var alStr = [];
        var O = function(x) { return x }
        for(var a in ar) {
            alStr.push(O.bind(null, ar[a]));
        }
        return alStr; 
    }
    
    var a = ["a", 24, 12345];
    var b = transform(a);
    console.log(a[2]);
    b[2]();
    
    这是一个更正确的范例,因为启动闭包具有非常明确的含义。然而,使用bind往往是一种函数方法,在函数调用时(在特定的上下文中或具有特定的规定)要特别使用

    使用with块也有一些缺点(关于它有很多问题)

    奖金:如果希望
    b
    也表示
    a
    数组的后续更改,此解决方案解决了该问题:

    function transform(ar) {
        var alStr = [];
        var O = function(x) { return ar[x] }
        for(var a in ar) {
            alStr.push(O.bind(null, a));
        }
        return alStr; 
    }
    
    var a = ["a", 24, 12345];
    var b = transform(a);
    console.log(a[2]);
    console.log(b[2]());
    console.log("*********");
    a[2] = "new value!";
    console.log(a[2]);
    console.log(b[2]());
    

    只有新函数引入新变量。。这个问题提得太多了。搜索“javascript循环最后一个值”或类似内容。请参阅以获得良好的解释。在非工作代码中,将
    var a
    放在
    for
    循环之前,这样可以更好地反映现实。对于
    for
    语句,没有本地变量,因为在JavaScript中,作用域总是由
    函数定义的。这意味着在
    for
    循环中创建的所有函数都引用同一个
    a
    变量,该变量是
    transform
    函数的本地变量。有关javascript中变量范围和提升的参考,请参阅。@32bitkid:您的两个链接都非常有用,非常感谢。第1点是我这边的输入错误,抱歉。仍在努力理解第二点。尽管这个答案是正确的,但我认为这里应该首选
    函数.bind
    。@daviditarenco很好,我更新了我的答案,并将+1添加到了你的答案中。
    使用了
    块技巧。这是我偶尔想到的一句话,但很少(从未)使用。我可能会更多地使用它,“带闭包”的例子实际上没有闭包。OP的第二个示例中的闭包才是问题所在,使用立即调用的函数表达式会破坏闭包。
    
    function transform(ar) {
        var alStr = [];
        var O = function(x) { return x }
        for(var a in ar) {
            alStr.push(O.bind(null, ar[a]));
        }
        return alStr; 
    }
    
    var a = ["a", 24, 12345];
    var b = transform(a);
    console.log(a[2]);
    b[2]();
    
    function transform(ar) {
        var alStr = [];
        var O = function(x) { return ar[x] }
        for(var a in ar) {
            alStr.push(O.bind(null, a));
        }
        return alStr; 
    }
    
    var a = ["a", 24, 12345];
    var b = transform(a);
    console.log(a[2]);
    console.log(b[2]());
    console.log("*********");
    a[2] = "new value!";
    console.log(a[2]);
    console.log(b[2]());