javascript - 关于一个闭包的例子
PHP中文网
PHP中文网 2017-04-11 11:34:34
[JavaScript讨论组]

这是《JavaScript高级程序设计》181页一个闭包的例子:

function createFunctions(){
    var result = new Array();
    
    for(var i = 0; i < 10; i++){
        result[i] = function(){
            return i;
        }
    }
    return result;
}

结果并不是每个函数都返回自己的索引值,而是每个函数都返回10,这是为什么?

其中书中这段代码上方一段文字种有这么一句话:

别忘了闭包所保存的是整个变量对象,而不是某个特殊变量。

请问这句话又是什么意思?谢谢各位

PHP中文网
PHP中文网

认证高级PHP讲师

全部回复(8)
天蓬老师

i变量只有一个,保存在作用域链中没有被销毁(因为闭包还在使用),所以,results[i]中每一个函数中的i变量始终都指向同一个变量。所以在for循环以后,i变量就变成了10,当执行闭包的时候,每一个函数去作用域链上找i变量,得到的结果就是10

阿神
result[i] = function(){
            return i;
        }

这里的i是个变量引用,循环完后i变成了10,返回的i全部指向10.

PHP中文网

主要是变量作用域的问题。
for中的i的声明可以理解等价于:

var i = 0;
for(; i < 10; i++){
    result[i] = function(){
        return i;
    }
}

循环中的匿名函数return的是i 而不是1,2,3
所以最终i的值是多少就return多少。
如果最后把i赋值为0, 函数返回就都是0, 就像:

function createFunctions(){
    var result = new Array();
    
    for(var i = 0; i < 10; i++){
        result[i] = function(){
            return i;
        }
    }
    i = 0;
    return result;
}

所以写一个立即执行函数把当时的i保留下来,匿名函数return的就是当时i的值了。
es6有let关键字, for中的var改成let可以替代闭包,如果是新建的nodejs的项目已经可以无视这个问题了,可以说是js的遗留的变量作用域问题

ringa_lee

var i 定义在函数createFunctions中,循环结束后i变成了10,其他所有新建的函数都是return 语句中引用同一个i,所以都返回10.

看下MDN

伊谢尔伦

别忘了闭包所保存的是整个变量对象,而不是某个特殊变量。

result[i]是个function。只是一个别名,并不是该function执行后返回的结果

这里是return i,而最后i的值为10,当然结果为10了

黄舟

造成返回结果总是1,是受作用域的影响。早期JavaScript没有块级作用域的概念,需要借助闭包模拟块级作用域。
代码实现

function createFunctions() {
    var result = new Array();

    for (var i = 0; i < 10; i++) {
        result[i] = (function(i) {
            return function() {
                return i;
            }
        })(i)
    }
    return result;
}

ES6中原生支持块级作用域,let
代码实现

function createFunctions() {
    var result = new Array();

    for (let i = 0; i < 10; i++) {
        result[i] = function () {
          return i
        }
    }
    return result;
}
巴扎黑

好多回答。。不知道你是不是已经看懂了

首先理解下作用域的概念,简单的说,在{}内产生的变量只在{}内有效, 如果有嵌套{ A { B } }的情况,内部域B可以得到外部域A中的变量,外部域A不能得到内部域B中的变量。

然后说下在这个例子里面为什么每个函数都返回10,i的这种声明方式等价于

var i = 0;
for(i;i<10;i++){...}

此时i的域是在外部的, 所以for里的作用域可以得到i这个值并且每次拿到的都是同一个i, 所以在function里的i拿到的也是同一个i, 注意

result[i] = function(){...}

这个操作只是一个赋值操作,function只是创建了但是并没有执行。

最后说下闭包,"正常情况下一个函数在运行结束后会销毁函数内部的所有变量来释放内存,当函数内部有变量为了保持被外部方法的调用而没有自动销毁的这个现象就是闭包",在这个例子里面正常来说执行完return result后就会销毁,但是如果result被赋值给外部的某个变量,比如说

var a = createFunctions();
a[0]();    //return 10;

这个时候a这个数组就可以执行来返回i这个变量, i这个变量为了保持外部a这个变量的调用而使得createFunctions这个函数没有销毁而被保存,这个就是闭包,上面是我对闭包的理解。

怪我咯

这里用的到是函数闭包的问题,可以看看阮一峰的博客

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

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