返回闭包的变量是创建副本而不是引用

时间:2017-02-25 16:15:56

标签: javascript closures

我对这种关闭行为感到困惑。我已经阅读了几篇关于闭包的SO文章(包括this one)和MDN的文档,但是没有看到这种行为的解释。

在下面的代码示例中,我创建了一个包含变量cache的闭包,一个修改它的函数preload,以及一个记录其值的函数report。它还将引用附加到传入的对象。

'use strict';

var o = {};

(function(obj) {
    var cache = {'initialized': false};

    function preload(assets, done) {
        console.log('Preloading. Value of cache is', cache);
        cache = {};

        for (var i = 0; i < assets.length; i++) {
            cache[assets[i]] = assets[i];
        }
    }

    function report() {
        console.log('Cache from inside is ', cache);
    }

    function get_cache() {
        return cache;
    }

    obj.cache = cache;
    obj.preload = preload;
    obj.report = report;
} )(o);

// {initialized: false}, as expected
o.report();

// {initialized: false}, as expected
console.log('Cache from outside is ', o.cache);

// I expect this to change cache to {1:1, 2:2, 3:3}
o.preload([1, 2, 3]);

// {1:1, 2:2, 3:3}, as expected
o.report();

// {initialized: false}, NOT as expected. Why?
console.log('Cache from outside is ', o.cache);

我的期望是基于我的理解,当闭包将cache附加到提供的obj时,它会在闭包中分配对变量的引用。但我看到的行为表明,obj.cache正在获取关闭cache副本

此时是cache创建的副本以及原因?

2 个答案:

答案 0 :(得分:2)

当您在开头调用obj.cache = cache;时,您obj.cache指向cache指向的同一对象(此对象:{'initialized': false}

稍后当您致电preload时,您将变量cache指向另一个新对象:cache = {};。现在cache变量指向一个全新的对象,而obj.cache仍然指向在开头创建的旧对象。

这解释了为什么在闭包内的cache上完成的所有日志都会记录新值,而记录obj.cache仍然显示未更改的值。它们现在指向2个不同的对象,并且更改cache现在指向的对象的内容对obj.cache指向的原始对象没有影响。

答案 1 :(得分:0)

当您IIFE被执行时,您已将cache添加到obj.cache,就是这样。 obj.cache并未对您cache中的IIFE变量进行引用。但是,reportpreload函数正在使用cache中的IIFE变量,即使它们是在创建它们的范围之外调用的。因此,IIFEobj.preload函数保留了对obj.report内部范围的引用(这是观察到闭包的地方),但不是obj.cache。< / p>

有关如何观察和行使关闭的各种情况的更多详细信息,请查看此link