美文网首页
闭包与循环

闭包与循环

作者: xiaoguo16 | 来源:发表于2017-08-21 22:26 被阅读0次

    先来一个例子:

    function A(){
        var m=[];
        for(var i=0;i<5;i++){
            m[i]=function () {
                return i
            }
        }
        return m;
    }
    var a=A()[0]
    a();//5
    

    上面的例子中数组m中保存的函数返回值都为5。

    why?

    上述例子中的a是匿名函数,而执行匿名函数时,匿名函数保存着外层函数的活动对象的引用,而它们引用的都是外层函数中的i,也就是引用的同一个值,所以都是最后的变量i。

    修改后:

    function A(){
        var m=[];
        for(var i=0;i<5;i++){
            m[i]=function(j){
                return function () {
                    return j;
                }
            }(i)
        }
        return m;
    }
    var a=A()[0]
    a();//0
    

    原理:

    利用函数传参的特点,函数传参是按值传递的,而非按引用,所以j中保存的是i的副本,也就是每次的值都是不同的。

    常见错误

    for(var i=1;i<=5;i++){
        setTimeout(function(){
            console.log(i);
        },i*1000)
    }
    //输出5个6;
    

    why?

    Paste_Image.png

    先运行主线程序,然后运行到setTimeout这个异步函数时,它会有一个延迟,此时该函数中的function丢入副线运行,主线继续执行,当执行完for循环后,此时在检查副线进程,发现副线已经到时间了,就传给它i值,但此时的i值已经变为6了,所以后面的function都是6。
    但是这里即便延迟为0,仍然是输出5个6,因为它们对i的引用为同一个值。

    解决方案

    for(var i=1;i<=5;i++){
        (function(j){
            setTimeout(function(){
                console.log(j)
            },1000)
        })(i)
    }
    //1,2,3,4,5
    

    利用函数的传参的性质,按值传递,所以j是i的副本,即分别为1,2,3,4,5。

    相关文章

      网友评论

          本文标题:闭包与循环

          本文链接:https://www.haomeiwen.com/subject/ndwhdxtx.html