在实现Closure特性(javascript)时陷入困境



作为一个javascript初学者,直到看到下面示例代码中的陷阱,我才意识到Closure特性。我试图修改代码以弹出许多C/c++/c#/Java程序员期望的结果,

" item1 1"

"第二条2"

" item3 3 "

挣扎了一个小时,我还是做不到。哪位javascript大师能教我怎么修改它吗?谢谢你。

function buildList(list) {
    var result = [];
    for (var i = 0; i < list.length; i++) {
        var item = 'item' + list[i];
        result.push( function() {alert(item + ' ' + list[i])} );
    }
    return result;
}
function testList() {
    var fnlist = buildList([1,2,3]);
    // Using j only to help prevent confusion -- could use i.
    for (var j = 0; j < fnlist.length; j++) {
        fnlist[j]();
    }
}
testList();

这个想法是创建一个闭包,它将被固定在里面。

  1. 你可以嵌套for的内容在一个直接的函数:

function buildList(list) {
    var result = [];
    for (var i = 0; i < list.length; i++) {
        (function(k){// k will equals i
          var item = 'item' + list[k];
          result.push( function() {alert(item + ' ' + list[k])} );
        })(i);// i in argument
    }
    return result;
}
function testList() {
    var fnlist = buildList([1,2,3]);
    for (var j = 0; j < fnlist.length; j++) fnlist[j]();
}
testList();

与编写其他函数相同:

function doStuff(k,arr,arr2){
    var item = 'item' + arr[k];
    arr2.push( function() {alert(item + ' ' + arr[k])});    
}
function buildList(list) {
    var result = [];
    for (var i = 0; i < list.length; i++) doStuff(i,list,result);
    return result;
}
function testList() {
    var fnlist = buildList([1,2,3]);
    for (var j = 0; j < fnlist.length; j++) fnlist[j]();
}
testList();

  • 使用最近的forEach(value, index, array)方法自动提供闭包:
  • function buildList(list) {
        var result=[];
        list.forEach(function(e){
            result.push(function(){alert('item'+e+' '+e)});
        });
        return result;
    }
    buildList([1,2,3]).forEach(function(e){e();});

    相当酷。

  • 使用ECMAScript 6 let (thanks elad.chen)
  • let可以代替var来作用域i在循环中的函数中:不再需要像(1)和(2)那样创建闭包。您只需要将item+list[i]部分移动到函数中。然而,let仅在严格模式下可用,而不是在所有浏览器中(例如,它仍然错过firefox)

    'use strict'
    function buildList(list) {
        var result = [];
        for(let i=0;i<list.length;i++) {
            result.push(function(){alert('item'+list[i]+' '+list[i])});
        }
        return result;
    }
    function testList() {
        var fnlist = buildList([1,2,3]);
        for (var j = 0; j < fnlist.length; j++) fnlist[j]();
    }
    testList();

    绝不是高手,只是学习而已:

       function buildList(list) {
        var result = [];
        for (var i = 0; i < list.length; i++) {
            var item = 'item' + list[i];
            result.push( (function() {alert(item + ' ' + list[i])}) ());
        }
        return result;
    }
    
    function testList() {
        var fnlist = buildList([1,2,3]);
    }
    testList();
    

    这可能是IIFE使用的好机会。演示:http://jsfiddle.net/zh02a69j/2/

    当您通过fnlist[j]()调用第一个函数时,您的i值是最后增加的值。你的函数将结果推到数组'看到'只是那个值,因为它没有立即执行,在循环中-它被定义,但没有执行。您可以让它立即执行(如IIFE),在循环中,然后脚本返回预期的输出。

    如果我犯了一些错误(致所有以前和将来的反对者:))-也请指导我。

    最新更新