Javascript 返回一个闭包';s变量正在创建副本而不是引用

Javascript 返回一个闭包';s变量正在创建副本而不是引用,javascript,closures,Javascript,Closures,我被这种闭包行为弄糊涂了。我已经阅读了好几篇SO文章(包括)和MDN关于闭包的文档,但还没有看到对这种行为的解释 在下面的代码示例中,我正在创建一个闭包,其中包含一个变量cache,一个修改它的函数preload,以及一个记录其值的函数report。它还将引用附加到传入的对象 'use strict'; var o = {}; (function(obj) { var cache = {'initialized': false}; function preload(asse

我被这种闭包行为弄糊涂了。我已经阅读了好几篇SO文章(包括)和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);
“严格使用”;
var o={};
(功能(obj){
变量缓存={'initialized':false};
功能预加载(资产,完成){
log('preload.Value of cache's',cache);
缓存={};
对于(var i=0;i
我的期望是基于我的理解,当闭包将
缓存
附加到提供的
obj
时,它将引用分配给闭包内的变量。但是我看到的行为表明,
obj.cache
正在获取闭包的
cache
的副本


调用
obj.cache=cache时,在哪一点创建了
缓存的副本?为什么
在开始时,您正在使
obj.cache
指向
cache
指向的同一对象(此对象:
{'initialized':false}

然后,稍后调用
preload
时,将变量
cache
指向另一个新对象:
cache={}。现在,
cache
变量指向一个全新的对象,而
obj.cache
仍然指向一开始创建的旧对象


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

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

然后,稍后调用
preload
时,将变量
cache
指向另一个新对象:
cache={}。现在,
cache
变量指向一个全新的对象,而
obj.cache
仍然指向一开始创建的旧对象


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

在执行
IIFE
时,您已经将
cache
添加到
obj.cache
中,就是这样
obj.cache
不包含对
IIFE
cache
变量的引用。但是,
report
preload
函数正在使用
cache
变量从
IIFE
,即使在创建它们的范围之外调用它们。因此,对于
obj.preload
obj.report
函数(这是观察闭包的地方),将保留对
iLife
内作用域的引用,但对于
obj.cache
则不保留


有关观察和执行闭包的各种情况的更多详细信息,请查看此信息。

在执行
iLife
时,您已将
cache
添加到
obj.cache
,就是这样
obj.cache
不包含对
IIFE
cache
变量的引用。但是,
report
preload
函数正在使用
cache
变量从
IIFE
,即使在创建它们的范围之外调用它们。因此,对于
obj.preload
obj.report
函数(这是观察闭包的地方),将保留对
iLife
内作用域的引用,但对于
obj.cache
则不保留


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

为什么不公开
get_cache
,而是公开
cache
变量的初始值?因为您正在复制:
cache={}
。请注意,唯一的闭包是变量
缓存
本身。变量
obj.cache
不是闭包,而是一个普通的引用/指针赋值,就像在C、Java或其他语言中一样。因此,它使
obj.cache
指向
cache
指向的同一对象,而不是变量
cache
本身。换句话说,
obj.cache=cache
将指针按值分配给cache(它会像大多数编程语言一样复制指针),为什么不公开
get_cache
而公开
cache
变量的初始值?因为您正在生成一个c