JavaScript作用域的一个问题?
伊谢尔伦
伊谢尔伦 2017-04-10 15:03:39
[JavaScript讨论组]

例如:

var outter = [];
function fun () {
    for (var i = 0; i < 4; i++) {
        var x = {};
        x.invoke = function () {
            console.log(i);
        };
        outter.push(x);
    }
}
fun();
console.log(outter[0].invoke());
console.log(outter[1].invoke());
console.log(outter[2].invoke());
console.log(outter[3].invoke());

结果是:4 4 4 4 。
fun()执行完毕以后局部变量不是释放掉了吗?怎么outter[0].invoke()还能访问到局部变量i?

伊谢尔伦
伊谢尔伦

小伙看你根骨奇佳,潜力无限,来学PHP伐。

全部回复(4)
迷茫

牵扯到js中函数作用域链和闭包的问题哦。

如果闭包对函数中的一个对象未来有引用的话,这个对象不会被释放哦

PHPz

你的 i 一直都在被使用中,你 fun(); 之后那个 i 就变成 4 了。
然后你之后的每一次 outter[0].invoke() 当然都是 4 了。

然后这个所谓的局部变量就永远不会被回收了,因为你的每个 outter[].invoke() 都要用到这个 i 。

正确的应该是

function fun () {
    for (var i = 0; i < 4; i++) {
        var x = {};
        x.invoke = i;
        outter.push(x);
    }
}

// 或者
function fun () {
    for (var i = 0; i < 4; i++) {
        (function(i){
            var x = {};
            x.invoke = function(){
                console.log(i);
            };
            outter.push(x);
        })(i);
    }
}

还有你的代码中 函数里面 为什么写那么多遍 console.log,你的 invoke() 函数不是已经有了 console.log() 的功能了?
直接 outter[1].invoke(); 不就直接输出了?

题外话:正确的使用工具才能事半功倍。

阿神

今天刚刚看到JavaScript高级程序设计(第3版)才发现书里面有个例子(7.2.1 闭包与变量)和我这个问题一样。

书中提到:作用域链的配置机制引出了一个副作用,即闭包只能取得包含函数中任何变量的最后一个值。但是可以通过创建另一个匿名函数强制让闭包的行为符合预期。

fun()函数执行完毕后,它的执行环境的作用域链会被销毁,但是它的活动对象仍然会留在内存中,直到匿名函数被销毁后才被销毁。

PHPz

fun执行后:

jsfunContext.AO = {
    i: 4,
    x: {
        invoke: <第四个 function 的引用>
    }
}

对于每个 invoke 函数创建时:

jsinvoke.[[Scope]] = [
    funContext.AO,
    globalContext.VO
]

每个 invoke 执行时,其上下文作用域链:

jsinvokeContext.Scope = [
    invokeContext.AO,
    funContext.AO, // invoke在这里访问到标识符 i, i === 4 
    globalContext.VO
]
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

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