一个关于Javascript的闭包问题,为什么函数值为16?
大家讲道理
大家讲道理 2017-04-11 11:59:52
[JavaScript讨论组]

为什么f1(),f2(),f3(),都是16,而不是1,4,9?谢谢

大家讲道理
大家讲道理

光阴似箭催人老,日月如移越少年。

全部回复(7)
高洛峰

因为等主程序运行完(for循环结束时),再调用push里面函数,这个时候i=4,加个闭包即可

function count() {
    var arr = [];
    for (var i=1; i<=3; i++) {
        arr.push(function (i) {
            return function(){
                return i*i
            };
        }(i));
    }
    return arr;
}
阿神

arr中的匿名函数在运行的时候,内部的循环早到结束了,i那时候是4。

阿神

代码中闭包作用域中i值为循环结束时的值,即为4。
所以调用f1 f2 f3 三个函数中保存的作用域中的i均为4,故三个函数调用的结果均为16;

阿神

arr[0],arr[1],arr[2]中存的都是匿名函数啊,所以当arr[0]()执行的时候再去找i,这时候i已经是 4了,所以是16啊

怪我咯

count()在结束时返回的是(function(),function(),function())三个函数。

所以,results[0],results[1],results[2]均为函数,即f1(),f2(),f3()均为函数,返回i * i

而在循环结束的时候,由于i++,i的值已经变为4,所以f1(),f2(),f3()均返回i*i,即4*4=16

怪我咯

for循环开始时就开始调用push里面的函数了,只不过指向i地址的值一直在变,最后i=4.导致数组里面指向i地址值也变为4了。

ringa_lee

现有的回答没有一个真正答在点子上的。三个值都一样要用作用域来解释,i 的值都是 4 要用闭包来解释

真实的原因在于内部的三个匿名函数,看似都在访问各自独立的 i,但是问题就在于这个 i 是外层的(var 定义的变量具有函数级作用域而且会提升),三个匿名函数共享了外层 count 的作用域里的 i

count 函数只调用了一次,而三个内部匿名函数在真正调用是发生在 count 调用之后,但是三个函数又含有对 i 的引用所以形成了一个闭包,变量 i 得到了保护。i 的值是循环结束之后的 4,这时候三个内部函数又共享了这个作用域,所以引用到的 i 的值都是 4

所以要想让结果是 1,4,9,就要让内部函数的访问的 i 与外层 count 函数隔离,可以像现在的采纳回答里面的那样用一个 IIFE 把内部匿名函数包裹起来(但那个不叫“加个闭包”),i 的值用参数传进去

或者另外一种方法就是用 ES6 里的 let 来定义 i。ES6 对 for 循环里的初始条件用 let 定义的变量有特殊处理,会把每次循环都重新定义一次,并且值使用上次循环结束的值作为当前循环的初始值。这样的话就解除了内部匿名函数对外层作用域的共享

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号